http
Go语言内置的net/http包十分的优秀,提供了HTTP客户端和服务端的实现。
1 变量
var NoBody = noBody{}NoBody 是一个 io.ReadCloser,没有字节。Read 始终返回 EOF,Close 始终返回 nil。它可以在传出客户端请求中使用,以显式表示请求具有零字节。但是,另一种方法是简单地将 [Request.Body] 设置为 nil。
2 常用函数
2.1 ListenAndServe
函数签名
func ListenAndServe(addr string, handler Handler) error启动一个 HTTP 服务器,监听指定地址。
监听一个TCP网络地址,使用Handler来处理连接上的请求
连接配置保持为TCP keep-alives
自动为每个接受的连接启用 TCP keep-alive 机制,防止长时间空闲连接占用资源。
Keep-alive 间隔由操作系统决定(通常约 1-2 小时)。
处理请求
对每个新连接,启动一个 goroutine 处理请求。
使用传入的
handler处理 HTTP 请求。若handler为nil,默认使用http.DefaultServeMux(全局多路复用器)。
错误返回
一般返回非空error
2.2 ListenAndServeTLS
函数签名
参数:
addr:监听的 TCP 地址,格式为"host:port"(如":443")。certFile:服务器证书文件路径(通常为.pem或.crt文件)。keyFile:服务器私钥文件路径(通常为.key文件)。handler:HTTP 请求处理器,若为nil,使用http.DefaultServeMux。
返回值:始终返回非
nil错误(如证书无效、权限不足等)。启用 HTTPS 加密通信
使用 TLS(Transport Layer Security) 协议加密客户端与服务端之间的数据传输。
默认支持 TLS 1.2 及以上版本(取决于 Go 版本),确保通信安全性。
证书与私钥要求
证书(
certFile):验证服务器身份,需包含完整的证书链(见下文)。私钥(
keyFile):用于解密客户端发送的加密数据,需严格保密。
证书链拼接规则
证书链格式:若证书由 CA 签发,
certFile应为 服务器证书 + 中间证书 + 根证书 的拼接(按顺序)。示例:
验证逻辑:客户端通过证书链逐级验证信任关系,若中间证书缺失,会导致某些客户端(如浏览器)提示证书错误。
2.3 HandleFunc
http.HandleFunc 是 Go 语言 net/http 包中的一个核心函数,用于向默认的 HTTP 请求多路复用器(DefaultServeMux)注册处理函数。当用户访问特定路径时,注册的处理函数会被调用。
函数签名
参数:
pattern:URL 路径模式(如"/hello"或"/user/")。handler:处理函数,需满足func(http.ResponseWriter, *http.Request)签名。
基于
DefaultServeMuxDefaultServeMux是全局默认的 HTTP 请求多路复用器。当调用
http.ListenAndServe(addr, nil)时,若handler参数为nil,则使用DefaultServeMux。
子树路径匹配
以斜杠
/结尾的模式表示一个子树路径,匹配该路径及其子路径
精确匹配
不以斜杠结尾的模式需完全匹配路径:
2.4 Handle
用于向默认的多路复用器(DefaultServeMux)注册路由的核心函数。与 http.HandleFunc 不同,它接受一个实现了 http.Handler 接口的对象,而非直接的处理函数。
函数签名
参数:
pattern:URL 路径模式(如"/api"或"/static/")。handler:必须实现http.Handler接口的对象(需定义ServeHTTP方法)。
注册
http.Handler对象 将自定义的处理器对象绑定到指定路径模式,允许更复杂的请求处理逻辑(例如状态管理、中间件链等)。基于
DefaultServeMux与
http.HandleFunc一样,依赖全局的DefaultServeMux。通过
http.ListenAndServe(addr, nil)自动启用。
2.4.1.1 http.HandleFunc 与 http.Handle 的区别
**
http.HandleFunc**:直接接受处理函数。**
http.Handle**:接受实现了http.Handler接口的对象。等价性:
http.HandleFunc是http.Handle的语法糖,以下代码等效:
2.5 func MaxBytesReader(w ResponseWriter, r io.ReadCloser, n int64) io.ReadCloser
作用:主要用于限制HTTP请求体(Request Body)的最大大小,防止客户端(无论是意外还是恶意)发送过大的请求,从而保护服务器资源免于被耗尽
w http.ResponseWriter:服务器的响应写入器。当请求体过大时,函数内部可能会利用它来确保连接被正确关闭或处理。
r io.ReadCloser:通常传入原始的请求体r.Body。它必须实现io.ReadCloser接口(即同时包含Read和Close方法)。
n int64:允许读取的请求体的最大字节数。
当从被包装的
r.Body中读取的数据量超过设定的n时:后续的读取操作会立即返回一个错误。
常见的错误信息是
"http: request body too large"。你需要在后续读取请求体的代码中(例如
io.ReadAll(r.Body)或json.NewDecoder(r.Body).Decode(...))检查并处理这个错误,通常向客户端返回http.StatusRequestEntityTooLarge(413) 状态码当
http.MaxBytesReader检测到读取的数据量超过设置的限制时,它不会立即向客户端发送响应,而是会在后续读取请求体(r.Body)时返回一个特定的错误。
调用后,它返回一个包装过的 io.ReadCloser,你应该用其替换原始的 r.Body。
3 常用类型
3.1 Handler
net/http 包中,http.Handler 是一个 接口类型,定义了 HTTP 请求处理器的核心行为。任何实现了该接口的类型都可以处理 HTTP 请求,是构建 Web 服务的核心抽象。
实现该接口的类型必须定义
ServeHTTP方法,用于处理 HTTP 请求并返回响应。http.ResponseWriter:用于写入响应头和响应体。*http.Request:包含客户端请求的所有信息。
任何需要处理 HTTP 请求的自定义逻辑都需要实现该接口。常见的实现方式包括:
自定义结构体:用于复杂逻辑或需要维护状态的场景。
函数适配器:将普通函数转换为
Handler接口。中间件:通过包装现有的
Handler添加额外功能。
3.1.1 http提供的Handler实现
3.1.1.1 FileServer(root FileSystem)
作用:用于托管静态文件。
托管前端静态资源(HTML、CSS、JavaScript)。
提供下载文件服务。
3.1.1.2 TimeoutHandler(h http.Handler, dt time.Duration, msg string)
作用:为处理器添加超时控制。
防止长时间阻塞的操作耗尽服务器资源。
对第三方 API 调用设置超时。
3.1.1.3 NotFoundHandler()
作用:返回一个固定响应
404 Not Found的处理器。
3.1.1.4 http.StripPrefix(prefix string, h http.Handler)
作用:移除请求路径的前缀后,再将请求转发给
h。托管静态文件时,去除 URL 前缀。
3.1.1.5 RedirectHandler(url string, code int)
作用:返回一个重定向到指定 URL 的处理器。
3.1.2 自定义Handler接口
3.2 HandlerFunc
HandlerFunc 是接口型函数模式最经典的实现。它完美展示了如何通过函数类型实现接口,极大简化 HTTP 处理器的编写。
设计精妙之处:
类型转换即实现:任何
func(ResponseWriter, *Request)函数都可转为Handler零成本抽象:没有额外内存分配
闭包友好:天然支持状态捕获
3.3 Dir类型
http.Dir 是 Go 语言 net/http 包中用于表示文件系统目录的类型,主要用于提供静态文件服务。它实现了 http.FileSystem 接口,允许通过 HTTP 访问指定目录下的文件。
本质:是
string类型的别名,表示文件系统的绝对或相对路径(如"./static")。实现接口:
http.FileSystem(需实现Open方法)。
3.3.1 Open(name string) (http.File, error)
作用:根据
name路径打开文件,返回http.File对象。逻辑:
路径拼接:将
http.Dir表示的目录与请求路径name合并。安全检查:清理路径中的
..,防止访问根目录外的文件。返回文件:若文件存在且可读,返回文件句柄;否则返回错误(如
os.ErrNotExist)。
3.4 FileSystem类型
http.FileSystem 是 Go 语言 net/http 包中用于抽象文件系统访问的接口类型,允许通过 HTTP 协议提供文件服务。它不限于物理磁盘文件,可以支持内存文件、嵌入式资源或云存储(如 S3)等。
3.5 Header类型
http.Header 是 Go 语言 net/http 包中用于操作 HTTP 头部信息的类型。它是一个键值对集合,键为字符串,值为字符串切片([]string),支持多值头部(如 Accept-Encoding: gzip, deflate)。
3.5.1 Get(key string) string
作用:获取键对应的第一个值。
3.5.2 Set(key, value string)
作用:设置键的值,覆盖所有现有值。
3.5.3 Add(key, value string)
作用:为键追加一个值,保留现有值。
3.5.4 Del(key string)
作用:删除键及其所有值。
3.5.5 Values(key string) []string
作用:获取键对应的所有值。
3.5.6 Write(w io.Writer) error
作用:将头部按 HTTP 格式写入
io.Writer
3.6 Request
http.Request 是 Go 语言 net/http 包中表示 HTTP 请求的核心结构体,它封装了客户端请求的所有信息,包括方法、URL、头、体等。
属性
Method:HTTP 请求方法(如
GET、POST、PUT等)。URL:解析后的请求 URL 信息,包含路径、查询参数等。
Path:请求路径(如/api/data)。RawQuery:原始查询字符串(如?name=foo&id=123)。Query():解析后的查询参数(返回url.Values类型)。
Header:HTTP 请求头信息。
Body:请求体数据流(如 POST 表单或 JSON 数据)。
读取后需关闭:
defer r.Body.Close()。不可重复读取,多次使用需缓存(如
ioutil.ReadAll)。
Form和PostForm
Form:合并 URL 查询参数和 POST 表单数据(需先调用ParseForm)。PostForm:仅包含 POST/PUT 表单数据(需先调用ParseForm)。
MultipartForm:解析后的多部分表单数据(如文件上传)。
Cookies():返回请求中的 Cookie 列表。
Context():获取请求的上下文(用于传递元数据或超时控制)。
3.6.1 ParseForm() error
作用:解析 URL 查询参数和
application/x-www-form-urlencoded类型的请求体。调用关系:在访问
r.Form或r.PostForm前必须调用。
3.6.2 FormValue(key string) string
作用:获取 URL 查询参数或 POST 表单中指定键的值(自动调用
ParseForm)。注意:若键存在多个值,返回第一个值。
3.6.3 func (r *Request) FormFile(key string) (multipart.File, *multipart.FileHeader, error)
作用:返回表单键提供的第一个文件,如有必要,FormFile 会调用 Request.ParseMultipartForm (默认的内存大小限制是 32MB)和 Request.ParseForm
接收一个字符串参数
key,这个key对应于HTML表单中文件上传输入框(<input type="file">)的name属性值multipart.File:一个实现了
io.Reader接口的对象,用于读取文件内容*multipart.FileHeader:包含文件的元数据,如文件名、大小和MIME信息
error:表示操作过程中是否发生错误
3.6.4 PostFormValue(key string) string
作用:仅获取 POST 表单中指定键的值(自动调用
ParseForm)。
3.6.5 ParseMultipartForm(maxMemory int64) error
作用:解析
multipart/form-data类型的请求体(如文件上传)。参数:
maxMemory指定内存缓存大小(超出部分写入临时文件)。调用此方法后,解析得到的所有表单数据(包括普通字段和上传的文件信息)会存储在
http.Request对象的MultipartForm字段中,此后你可以通过该字段或其它辅助方法来访问数据
3.6.6 Cookie(name string) (*Cookie, error)
作用:获取指定名称的 Cookie。
3.6.7 WithContext(ctx context.Context) *Request
作用:创建绑定新上下文的新请求(常用于中间件传递数据或超时控制)。
3.7 ResponseWriter
http.ResponseWriter 是 Go 语言 net/http 包中用于构建 HTTP 响应的核心接口,它定义了服务端向客户端发送响应的基本操作。
Header() http.Header:返回响应头的
Header对象(map[string][]string),用于设置头信息。必须在调用
WriteHeader或Write之前 设置头信息,否则可能不生效。头信息键名自动转换为 首字母大写(如
content-type→Content-Type)。
Write([]byte) (int, error):向响应体写入数据(如 HTML、JSON、二进制流等)。
如果未调用
WriteHeader,第一次调用Write时会自动触发WriteHeader(http.StatusOK)。支持多次调用,数据会 追加 到响应体中。
WriteHeader(statusCode int): 显式设置 HTTP 状态码(如
200、404等)。只能调用一次,重复调用会触发日志警告:
http: superfluous response.WriteHeader call。必须在
Write之前 调用,否则状态码可能被默认设为200。
3.8 ServeMux
http.ServeMux 是 Go 语言 net/http 包中用于管理 HTTP 请求路由的核心类型,它是一个 HTTP 请求多路复用器(即路由管理器),负责将不同路径的请求分发到对应的处理器。
mu:读写锁,用于保护路由表(
tree、index等字段)的并发安全。写操作(如注册路由
Handle/HandleFunc)会获取写锁(Lock),阻塞其他读写。读操作(如处理请求
ServeHTTP)会获取读锁(RLock),允许多个读并行。
tree:表示路由的 前缀树(Trie 树) 结构,用于高效匹配 URL 路径。
index:路由索引,用于加速特定场景下的查找(如按主机名分类或路径前缀)。
patterns:存储所有已注册的路由模式(如
/api、/user/{id})。mux121:旧版路由复用器(如 Go 1.21 之前的实现),通过
GODEBUG=httpmuxgo121=1启用,用于兼容性测试或回退。
3.8.1 NewServeMux() *ServeMux
作用:创建一个新的ServeMux对象
3.8.2 Handle(pattern string, handler http.Handler)
作用:将
handler注册到指定的路径模式pattern。pattern:URL 路径匹配模式(如"/api"或"/static/")。handler:实现了http.Handler接口的对象。
3.8.3 HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
作用:将函数
handler转换为http.Handler并注册到pattern。
3.8.4 Handler(r *http.Request) (handler http.Handler, pattern string)
作用:根据请求
r查找匹配的处理器和路径模式。一般用于中间件或自定义路由逻辑,较少直接调用。
3.8.5 ServeHTTP(w http.ResponseWriter, r *http.Request)
作用:实现
http.Handler接口,处理请求并调用匹配的处理器。用户通常不直接调用此方法,由
http.Server自动触发。
3.9 路径匹配
ServeMux 的路径匹配遵循以下优先级规则,且区分大小写:
最长路径优先: 例如,注册了
/和/api,请求/api会匹配后者。子树路径匹配: 以
/结尾的模式(如/images/)会匹配该路径及其子路径(如/images/1.jpg)。精确匹配: 不以
/结尾的模式(如/about)仅匹配完全相同的路径(不匹配/about/)。
3.10 Client
http.Client是Go语言net/http包中用于发送HTTP请求并接收HTTP响应的核心结构体。
Transport
RoundTripper接口
指定HTTP事务(请求-响应)的完整运行机制,是客户端最核心的组件,负责连接管理、协议细节等底层传输逻辑。
http.DefaultTransport
1. 连接池:默认的 DefaultTransport会维护连接池以复用连接,提升性能。关键配置包括 MaxIdleConns(总最大空闲连接数,默认100)和 MaxIdleConnsPerHost(每主机最大空闲连接数,默认2,此值过小可能导致高并发时频繁建连)
。
2. 自定义:可实现自定义的 RoundTripper以控制代理、TLS、压缩等底层细节
。
3. 超时:Transport本身可设置更细粒度的超时(如 DialContext.Timeout, TLSHandshakeTimeout),这与 Client.Timeout是互补的
。
CheckRedirect
func(req *Request, via []*Request) error
定义处理HTTP重定向的策略。当收到3xx响应时,客户端在跟随重定向前会调用此函数。
默认策略:在10次连续重定向后停止 。
1. 控制逻辑:可通过此函数限制重定向次数、记录重定向路径或根据特定条件(如URL)中止重定向
。
2. 特殊错误:若函数返回 http.ErrUseLastResponse,则客户端返回最近一个响应且不关闭其Body,并返回 nil错误
。
示例:func(req *http.Request, via []*http.Request) error { if len(via) >= 5 { return fmt.Errorf("stopped after %d redirects", len(via)) } return nil }
Jar
CookieJar接口
管理Cookie的容器。自动存储响应中的Cookie,并在后续出站请求中自动添加相关的Cookie。
nil
1. 默认行为:如果为 nil,则只有在请求上显式设置的Cookie才会被发送,响应中的Cookie会被忽略
。
2. 使用:通常使用 cookiejar.New(nil)创建Jar实例
。该Jar是内存型的,程序重启后Cookie会丢失。如需持久化,需自行实现。
Timeout
time.Duration
设置客户端每次请求从开始到结束(包括重定向、读取响应体)的总时间限制。
复用Client实例:
http.Client是并发安全的,其底层的Transport维护了连接池。强烈建议在应用程序中复用同一个Client实例(或极少数几个配置不同的实例),而不是为每个请求都创建新的Client。这可以避免不必要的连接建立与销毁开销,并有效利用连接池。资源清理:使用
Client发送请求后,必须关闭响应体(resp.Body.Close()),通常使用defer语句确保执行。这是为了将连接返回到连接池以供复用,否则可能导致资源(如文件描述符)泄漏。默认客户端:包级别的便捷函数(如
http.Get,http.Post)使用默认的http.DefaultClient。它是一个没有设置超时的基本客户端,在生产环境中直接使用需谨慎,最好根据需求创建具有适当配置(尤其是Timeout)的自定义Client。
3.10.1 Get
定义:
func (c *Client) Get(url string) (resp *Response, err error)用途: 向指定URL发起GET请求。适用于简单的数据获取。
注意: 非2xx状态码(如404、500)不会被该方法认为是错误,你需要检查
resp.StatusCode。
3.10.2 Post 和 PostForm
定义:
func (c *Client) Post(url, contentType string, body io.Reader) (resp *Response, err error)func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error)
用途: Post用于发送自定义内容类型(如JSON)的数据。PostForm专用于发送表单数据(
application/x-www-form-urlencoded)。
3.10.3 DO
定义:
func (c *Client) Do(req *Request) (*Response, error)用途: 这是最基础、最强大的方法。
Get,Post等方法内部都调用了Do。当需要设置自定义请求头、使用特定上下文(Context)或更精细地控制请求时,必须使用Do方法。
关键提醒:
如果返回的
err为nil,必须在读取完响应体后调用resp.Body.Close()来释放网络连接,使其能被连接池复用。通常使用defer来确保执行。错误可能由客户端策略(如重定向检查失败)或HTTP协议问题(如网络连接失败)引起。非2xx状态码不会导致错误
3.10.4 CloseIdleConnections
定义:
func (c *Client) CloseIdleConnections()用途: 关闭客户端传输层中所有处于空闲(keep-alive)状态的连接。它不会中断正在使用的连接。通常在应用程序退出或明确知道一段时间内不会有新请求时调用,有助于释放系统资源
3.10.5 注意事项
资源管理:务必关闭响应体
这是最重要也是最容易出错的一点。只要
client.Do,Get,Post等函数返回的err为nil,你就必须在处理完响应后关闭resp.Body。使用defer是确保这一操作得以执行的最佳方式。
错误处理:区分网络错误与HTTP错误
网络/协议错误:会在
err中体现,如超时、DNS解析失败、连接被拒绝等。HTTP错误:指4xx, 5xx等状态码。这些不会使
err不为nil,你需要手动检查resp.StatusCode。
性能优化:复用Client实例
http.Client是并发安全的,其内部通过Transport机制管理连接池。绝对不要为每个HTTP请求都创建一个新的Client。应该在程序生命周期内复用同一个(或少量几个配置不同的)Client实例,这样可以极大提升性能,避免频繁建立和断开TCP连接确保连接能被复用的正确操作包括两个步骤:将响应体读取完毕和关闭响应体。
读取完毕:这是为了将连接中的残留数据清空,为下一个请求准备好一个“干净”的连接。如果你不关心响应内容,也需要将其读取并丢弃。
关闭响应体:这是最关键的一步,它会通知底层的
Transport:“这个连接我已经用完了,请把它收回到连接池里。”
配置超时
永远不要使用无限期等待的默认客户端(
http.DefaultClient没有设置超时)。为你的客户端设置合理的超时时间,防止请求无限期挂起,这对生产环境的稳定性至关重要。
Get
快速发起简单的GET请求
低
是
是
Post/PostForm
快速发起简单的POST请求(JSON或表单)
低
是
是
Do
需要高度自定义的请求(如设置Header、Context、使用非标准方法)
极高
遵循客户端配置
是
http.Client的高性能很大程度上得益于其底层的连接池机制,由Transport类型管理
。了解几个关键配置有助于优化高频请求场景:
MaxIdleConnsPerHost:默认值为2。这表示对同一个目标主机,最多只保持2个空闲连接。在高并发场景下,此值设置过小可能导致需要频繁创建新连接。可以根据需要适当调大。
DisableKeepAlives:默认为
false,即启用长连接(连接复用)。除非有特殊理由,否则不应禁用。IdleConnTimeout:空闲连接在连接池中保留的最长时间,超时后连接将被关闭。
最后更新于