Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >go http 服务器编程(2)

go http 服务器编程(2)

作者头像
李海彬
发布于 2018-03-23 06:40:35
发布于 2018-03-23 06:40:35
1.4K00
代码可运行
举报
文章被收录于专栏:Golang语言社区Golang语言社区
运行总次数:0
代码可运行

match 会遍历路由信息字典,找到所有匹配该路径最长的那个。路由部分的代码解释就到这里了,最后回答上面的一个问题:http.HandleFuncServeMux.HandlerFunc 是什么关系?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Handle registers the handler for the given pattern
// in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }

// HandleFunc registers the handler function for the given pattern
// in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
	DefaultServeMux.HandleFunc(pattern, handler)
}

原来是直接通过 DefaultServeMux 调用对应的方法,到这里上面的一切都串起来了!

Request

最后一部分,要讲讲 Handler 函数接受的两个参数:http.Requesthttp.ResponseWriter

Request 就是封装好的客户端请求,包括 URL,method,header 等等所有信息,以及一些方便使用的方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// A Request represents an HTTP request received by a server
// or to be sent by a client.
//
// The field semantics differ slightly between client and server
// usage. In addition to the notes on the fields below, see the
// documentation for Request.Write and RoundTripper.
type Request struct {
	// Method specifies the HTTP method (GET, POST, PUT, etc.).
	// For client requests an empty string means GET.
	Method string

	// URL specifies either the URI being requested (for server
	// requests) or the URL to access (for client requests).
	//
	// For server requests the URL is parsed from the URI
	// supplied on the Request-Line as stored in RequestURI.  For
	// most requests, fields other than Path and RawQuery will be
	// empty. (See RFC 2616, Section 5.1.2)
	//
	// For client requests, the URL's Host specifies the server to
	// connect to, while the Request's Host field optionally
	// specifies the Host header value to send in the HTTP
	// request.
	URL *url.URL

	// The protocol version for incoming requests.
	// Client requests always use HTTP/1.1.
	Proto      string // "HTTP/1.0"
	ProtoMajor int    // 1
	ProtoMinor int    // 0

	// A header maps request lines to their values.
	// If the header says
	//
	//	accept-encoding: gzip, deflate
	//	Accept-Language: en-us
	//	Connection: keep-alive
	//
	// then
	//
	//	Header = map[string][]string{
	//		"Accept-Encoding": {"gzip, deflate"},
	//		"Accept-Language": {"en-us"},
	//		"Connection": {"keep-alive"},
	//	}
	//
	// HTTP defines that header names are case-insensitive.
	// The request parser implements this by canonicalizing the
	// name, making the first character and any characters
	// following a hyphen uppercase and the rest lowercase.
	//
	// For client requests certain headers are automatically
	// added and may override values in Header.
	//
	// See the documentation for the Request.Write method.
	Header Header

	// Body is the request's body.
	//
	// For client requests a nil body means the request has no
	// body, such as a GET request. The HTTP Client's Transport
	// is responsible for calling the Close method.
	//
	// For server requests the Request Body is always non-nil
	// but will return EOF immediately when no body is present.
	// The Server will close the request body. The ServeHTTP
	// Handler does not need to.
	Body io.ReadCloser

	// ContentLength records the length of the associated content.
	// The value -1 indicates that the length is unknown.
	// Values >= 0 indicate that the given number of bytes may
	// be read from Body.
	// For client requests, a value of 0 means unknown if Body is not nil.
	ContentLength int64

	// TransferEncoding lists the transfer encodings from outermost to
	// innermost. An empty list denotes the "identity" encoding.
	// TransferEncoding can usually be ignored; chunked encoding is
	// automatically added and removed as necessary when sending and
	// receiving requests.
	TransferEncoding []string

	// Close indicates whether to close the connection after
	// replying to this request (for servers) or after sending
	// the request (for clients).
	Close bool

	// For server requests Host specifies the host on which the
	// URL is sought. Per RFC 2616, this is either the value of
	// the "Host" header or the host name given in the URL itself.
	// It may be of the form "host:port".
	//
	// For client requests Host optionally overrides the Host
	// header to send. If empty, the Request.Write method uses
	// the value of URL.Host.
	Host string

	// Form contains the parsed form data, including both the URL
	// field's query parameters and the POST or PUT form data.
	// This field is only available after ParseForm is called.
	// The HTTP client ignores Form and uses Body instead.
	Form url.Values

	// PostForm contains the parsed form data from POST or PUT
	// body parameters.
	// This field is only available after ParseForm is called.
	// The HTTP client ignores PostForm and uses Body instead.
	PostForm url.Values

	// MultipartForm is the parsed multipart form, including file uploads.
	// This field is only available after ParseMultipartForm is called.
	// The HTTP client ignores MultipartForm and uses Body instead.
	MultipartForm *multipart.Form

	...

	// RemoteAddr allows HTTP servers and other software to record
	// the network address that sent the request, usually for
	// logging. This field is not filled in by ReadRequest and
	// has no defined format. The HTTP server in this package
	// sets RemoteAddr to an "IP:port" address before invoking a
	// handler.
	// This field is ignored by the HTTP client.
	RemoteAddr string
    ...
}

Handler 需要知道关于请求的任何信息,都要从这个对象中获取,一般不会直接修改这个对象(除非你非常清楚自己在做什么)!

ResponseWriter

ResponseWriter 是一个接口,定义了三个方法:

  • Header():返回一个 Header 对象,可以通过它的 Set() 方法设置头部,注意最终返回的头部信息可能和你写进去的不完全相同,因为后续处理还可能修改头部的值(比如设置Content-LengthContent-type 等操作)
  • Write(): 写 response 的主体部分,比如 html 或者 json 的内容就是放到这里的
  • WriteHeader():设置 status code,如果没有调用这个函数,默认设置为 http.StatusOK, 就是 200 状态码
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// A ResponseWriter interface is used by an HTTP handler to
// construct an HTTP response.
type ResponseWriter interface {
	// Header returns the header map that will be sent by WriteHeader.
	// Changing the header after a call to WriteHeader (or Write) has
	// no effect.
	Header() Header

	// Write writes the data to the connection as part of an HTTP reply.
	// If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK)
	// before writing the data.  If the Header does not contain a
	// Content-Type line, Write adds a Content-Type set to the result of passing
	// the initial 512 bytes of written data to DetectContentType.
	Write([]byte) (int, error)

	// WriteHeader sends an HTTP response header with status code.
	// If WriteHeader is not called explicitly, the first call to Write
	// will trigger an implicit WriteHeader(http.StatusOK).
	// Thus explicit calls to WriteHeader are mainly used to
	// send error codes.
	WriteHeader(int)
}

实际上传递给 Handler 的对象是:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// A response represents the server side of an HTTP response.
type response struct {
	conn          *conn
	req           *Request // request for this response
	wroteHeader   bool     // reply header has been (logically) written
	wroteContinue bool     // 100 Continue response was written

	w  *bufio.Writer // buffers output in chunks to chunkWriter
	cw chunkWriter
	sw *switchWriter // of the bufio.Writer, for return to putBufioWriter

	// handlerHeader is the Header that Handlers get access to,
	// which may be retained and mutated even after WriteHeader.
	// handlerHeader is copied into cw.header at WriteHeader
	// time, and privately mutated thereafter.
	handlerHeader Header
	...
	status        int   // status code passed to WriteHeader
    ...
}

它当然实现了上面提到的三个方法,具体代码就不放到这里了,感兴趣的可以自己去看。

6. 扩展

虽然 net/http 提供的各种功能已经满足基本需求了,但是很多时候还不够方便,比如:

  • 不支持 URL 匹配,所有的路径必须完全匹配,不能捕获 URL 中的变量,不够灵活
  • 不支持 HTTP 方法匹配
  • 不支持扩展和嵌套,URL 处理都在都一个 ServeMux 变量中

虽然这些都可以自己手动去码,但实在很不方便。这部分看看有哪些三方的包,都提供了哪些额外的功能。

alice

alice 的功能很简单——把多个 handler 串联起来,有请求过来的时候,逐个通过这个 handler 进行处理。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
alice.New(Middleware1, Middleware2, Middleware3).Then(App)

Gorilla Mux

Gorilla 提供了很多网络有关的组件, Mux 就是其中一个,负责 HTTP 的路由功能。这个组件弥补了上面提到的 ServeMux 的一些缺陷,支持的功能有:

  • 更多的匹配类型:HTTP 方法、query 字段、URL host 等
  • 支持正则表达式作为 URL path 的一部分,也支持变量提取功能
  • 支持子路由,也就是路由的嵌套,SubRouter 可以实现路由信息的传递
  • 并且和 ServeMux 完全兼容
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
r := mux.NewRouter()
r.HandleFunc("/products/{key}", ProductHandler)
r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)

httprouter

httprouter 和 mux 一样,也是扩展了自带 ServeMux 功能的路由库。它的主要特点是速度快、内存使用少、可扩展性高(使用 radix tree 数据结构进行路由匹配,路由项很多的时候速度也很快)。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (
    "fmt"
    "github.com/julienschmidt/httprouter"
    "net/http"
    "log"
)

func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
    fmt.Fprint(w, "Welcome!\n")
}

func Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
    fmt.Fprintf(w, "hello, %s!\n", ps.ByName("name"))
}

func main() {
    router := httprouter.New()
    router.GET("/", Index)
    router.GET("/hello/:name", Hello)

    log.Fatal(http.ListenAndServe(":8080", router))
}

negroni

http middleware 库,支持嵌套的中间件,能够和其他路由库兼容。同时它也自带了不少 middleware 可以使用,比如RecoveryLoggerStatic

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
router := mux.NewRouter()
router.HandleFunc("/", HomeHandler)

n := negroni.New(Middleware1, Middleware2)
// Or use a middleware with the Use() function
n.Use(Middleware3)
// router goes last
n.UseHandler(router)

http.ListenAndServe(":3001", n)

7. 参考

这篇文章参考了以下资料:

  • golang net/http 官方文档
  • net/http 源码
  • A Recap of Request Handling in Go
  • Not Another Go/Golang net/http Tutorial
  • the http handlerfunc wrapper technique in golang
  • why do all golang url routers suck

本文来自:开源中国博客

感谢作者:柠檬酷

查看原文:go http 服务器编程

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2016-11-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Golang语言社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Golang:深入理解http服务开发原理
http 是典型的 C/S 架构,客户端向服务端发送请求(request),服务端做出应答(response)。
公号:咻咻ing
2019/10/22
1.7K0
Go语言经典库使用分析(七)| 高性能可扩展 HTTP 路由 httprouter
Go语言(golang)的一个很大的优势,就是很容易的开发出网络后台服务,而且性能快,效率高。在开发后端HTTP网络应用服务的时候,我们需要处理很多HTTP的请求访问,比如常见的API服务,我们就要处理很多HTTP请求,然后把处理的信息返回给使用者。对于这类需求,Golang提供了内置的net/http包帮我们来处理这些HTTP请求,让我们可以比较方便的开发一个HTTP服务。
飞雪无情
2020/02/10
1.2K0
摸鱼快报:golang net/http中的雕虫小技
前端使用Create React App脚手架,默认以localhost:3000端口启动; 后端使用golang-gin框架,使用8034端口启动。 登录模块走的是sso,前后端分离,后端需要向前端写入认证cookie
有态度的马甲
2023/04/27
4670
摸鱼快报:golang net/http中的雕虫小技
go进阶-GO创建web服务+websocket详解
go提供了一系列用于创建web服务器的标准,而非常简单。只需要调用net/http包中的ListenAndServe函数并传入网络地址和负责处理的处理器就ok了。net/http库实现了整套的http服务中的客户端、服务端接口,可以基于此轻松的发起HTTP请求或者对外提供HTTP服务。
黄规速
2024/05/24
2.4K0
go进阶-GO创建web服务+websocket详解
Go 源码学习之--net/http
其实自己不是很会看源码,但是学习优秀的源码是提升自己代码能力的一种方式,也可以对自己以后写代码有一个很好的影响,所以决定在之后的时间内,要有一个很好的习惯,阅读优秀的源码。刚开始自己会觉得看源码很痛苦,这个和我自己的方法有关系,刚开始自己总是想要知道源码的每一步操作,以及每个部分都是做什么,导致看着看着就看不下去了,所以也是从这次整理开始,调整自己阅读源码的方式,先去源码框架的主要流程,细枝末节后面等对整体框架有个了解,并且很清晰了,再回头来细致看,所以阅读过程中如果有不理解的地方自己先进行跳过,先对主体的
coders
2018/03/30
1.8K0
Go 源码学习之--net/http
Go 语言 Web 编程系列(三)—— 基于官方标准库自定义路由处理器
我们在上篇教程介绍过这段代码的底层实现,这里 http.ListenAndServe 方法第二个参数传入的是 nil,表示底层会使用默认的 DefaultServeMux 实现将上述 HandleFunc 方法传入的处理函数转化为基于闭包方式定义的路由:
学院君
2019/12/20
9540
Go 语言 Web 编程系列(三)—— 基于官方标准库自定义路由处理器
「Go工具箱」一文读懂主流web框架中路由的实现原理
大家好,我是渔夫子。本号新推出「Go工具箱」系列,意在给大家分享使用go语言编写的、实用的、好玩的工具。同时了解其底层的实现原理,以便更深入地了解Go语言。
Go学堂
2023/01/31
7960
[Introduction]万字手撕Go http源码server.go
从路由注册到监听本地端口后请求路由的一系列动作的分析,基本上仅限于net/http server.go这个包文件的路由相关部分解读
Wzy_CC
2020/08/28
1.3K0
go http 服务器编程(1)
1. 初识 http 是典型的 C/S 架构,客户端向服务端发送请求(request),服务端做出应答(response)。 golang 的标准库 net/http 提供了 http 编程有关的接口,封装了内部TCP连接和报文解析的复杂琐碎的细节,使用者只需要和 http.request 和 http.ResponseWriter 两个对象交互就行。也就是说,我们只要写一个 handler,请求会通过参数传递进来,而它要做的就是根据请求的数据做处理,把结果写到 Response 中。废话不多说,来看看 h
李海彬
2018/03/23
4.7K0
go http 服务器编程(1)
深入学习用Go编写HTTP服务器
Go是一门通用的编程语言,想要学习 Go 语言的 Web 开发,就必须知道如何用 Go 启动一个 HTTP 服务器用于接收和响应来自客户端的 HTTP 请求。用 Go实现一个http server非常容易,Go 语言标准库net/http自带了一系列结构和方法来帮助开发者简化 HTTP 服务开发的相关流程。因此,我们不需要依赖任何第三方组件就能构建并启动一个高并发的 HTTP 服务器。这篇文章会学习如何用net/http自己编写实现一个HTTP Serverk并探究其实现原理,以此来学习了解网络编程的常见范式以及设计思路。
KevinYan
2020/02/17
2.5K0
深入学习用Go编写HTTP服务器
Go Web编程--给自己写的服务器添加错误和访问日志
错误日志和访问日志是一个服务器必须支持的功能,我们教程里使用的服务器到目前为止还没有这两个功能。正好前两天也写了篇介绍logrus日志库的文章,那么今天的文章里就给我们自己写的服务器加上错误日志和访问日志的功能。在介绍添加访问日志的时候会介绍一种通过编写中间件获取HTTP响应的StausCode和Body的方法。
KevinYan
2020/03/31
1.3K0
Go Web编程--给自己写的服务器添加错误和访问日志
golang(GO语言)http详解简单基础
因为好像长时间的写PHP可能大家感觉烦躁了,所以写一点golang的东西大家可以拿去玩玩,golang在web开发中让你得心应手,其实也是很好的东西,只要你玩进去之后感觉好爽,感觉比PHP的好处就是没有那么多的“限制”,基础部分大家可以看下简单的我再前边更新了一点点后边会继续给大家补上的,以后就是PHP+golang也可能会写一些object-c的,废话不多说开始写了,所有的代码我放在BUYVM上搭建的GOweb 大家可以去http://www.lingphp.com:8080/demo/查看获取完整代码,
李海彬
2018/03/22
1.5K0
go net/http标准库源码
可以看到 Go 实现的http服务步骤非常简单,首先注册路由,然后创建服务并开启监听即可。
leobhao
2024/04/01
1310
图文吃透Golang net/http 标准库--服务端
今天分享下Go语言net/http标准库的实现逻辑,文章将从客户端(Client)--服务端(Server)两个方向作为切入点,进而一步步分析http标准库内部是如何运作的。
小许code
2024/01/29
6280
图文吃透Golang net/http 标准库--服务端
Go 每日一库之 net/http(基础和中间件)
几乎所有的编程语言都以Hello World作为入门程序的示例,其中有一部分以编写一个 Web 服务器作为实战案例的开始。每种编程语言都有很多用于编写 Web 服务器的库,或以标准库,或通过第三方库的方式提供。Go 语言也不例外。本文及后续的文章就去探索 Go 语言中的各个Web 编程框架,它们的基本使用,阅读它们的源码,比较它们优缺点。让我们先从 Go 语言的标准库net/http开始。标准库net/http让编写 Web 服务器的工作变得非常简单。我们一起探索如何使用net/http库实现一些常见的功能或模块,了解这些对我们学习其他的库或框架将会很有帮助。
用户7731323
2021/07/23
1.3K0
golang-net/http源码分析之http server
第一时间获取文章,可以关注本人公众号 月牙寂道长 yueyajidaozhang
月牙寂道长
2018/03/06
1.7K0
package http
要管理代理、TLS配置、keep-alive、压缩和其他设置,创建一个Transport:
李海彬
2018/07/26
4K0
package http
理解Go语言Web编程(下)
ListenAndServe函数 前面所有示例程序中,都在main函数中调用了ListenAndServe函数。下面对此函数所做的工作进行分析。该函数的实现为: func ListenAndServe(addr string, handler Handler) error { server := &Server{Addr: addr, Handler: handler} return server.ListenAndServe() } 该函数新建了一个Server对象,然后调用该Server的L
李海彬
2018/03/22
2.2K0
【转】Go语言Http Server源码阅读
目录(?)[-] 前言 几个重要概念 具体分析 几个接口 Handler ResponseWriter Flusher Hijacker response HandlerFunc ServerMux
李海彬
2018/03/19
9020
golang构建http服务
除去细节,理解HTTP构建的网络应用只要关注两个端--客户端(client)和服务端(server),两个端的交互来自client的request,以及server端的response。所谓的http服务器,主要在于如何接受client的request,并向client返回response。
若与
2019/03/19
1.8K0
golang构建http服务
相关推荐
Golang:深入理解http服务开发原理
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验