net/http包详解
你想要全面了解 Go 语言中 net/http 包的核心功能、使用方式,并掌握其中的关键方法,这是学习 Go 后端开发的核心知识点之一。
net/http 是 Go 标准库中用于处理 HTTP 协议的核心包,它既可以快速搭建 HTTP 服务器,也能作为客户端发送 HTTP 请求,设计简洁且高性能,是 Go 做 Web 开发的基础。下面我会从服务器端、客户端、核心类型与方法三个维度,全面讲解这个包。
一、核心概念与整体架构
net/http 包的核心设计围绕两个核心角色:
- Server(服务器):监听端口、接收请求、路由分发、处理响应。
- Client(客户端):构造请求、发送请求、接收响应。
核心类型包括:ServeMux(路由多路复用器)、Handler(请求处理器)、Request(请求对象)、Response(响应对象)等。
二、服务器端:搭建 HTTP 服务
1. 最简 HTTP 服务器(快速入门)
通过 http.HandleFunc 注册路由处理函数,http.ListenAndServe 启动服务:
Go package main
import ( "fmt" "net/http" )
// 处理根路径请求的函数(符合 http.HandlerFunc 签名) func helloHandler(w http.ResponseWriter, r *http.Request) { // w:响应写入器,用于向客户端返回数据;r:请求对象,包含客户端请求的所有信息 fmt.Fprintf(w, "Hello, Go HTTP! Path: %s", r.URL.Path) }
func main() { // 1. 注册路由:将路径 "/" 与处理函数绑定 http.HandleFunc("/", helloHandler)
// 2. 启动 HTTP 服务,监听 8080 端口 // 第一个参数:监听地址(":8080" 表示所有网卡的 8080 端口) // 第二个参数:路由多路复用器(nil 表示使用默认的 DefaultServeMux) fmt.Println("Server starting on :8080...") err := http.ListenAndServe(":8080", nil) if err != nil { fmt.Printf("Server failed: %v\n", err) } } |
运行后访问 http://localhost:8080,即可看到响应内容。
2. 服务器端核心类型与方法
(1)http.Handler 接口(核心处理器)
所有能处理 HTTP 请求的类型都必须实现这个接口,定义如下:
Go type Handler interface { ServeHTTP(ResponseWriter, *Request) } |
自定义处理器示例(实现 Handler 接口):
Go type MyHandler struct{}
// 实现 ServeHTTP 方法 func (h *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Custom Handler!")) }
func main() { handler := &MyHandler{} http.Handle("/custom", handler) // 注册自定义处理器 http.ListenAndServe(":8080", nil) } |
(2)http.HandlerFunc(函数适配器)
本质是一个类型,实现了 Handler 接口,允许将普通函数(签名为 func(ResponseWriter, *Request))作为处理器:
Go type HandlerFunc func(ResponseWriter, *Request)
// 实现 ServeHTTP 方法,调用自身 func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { f(w, r) } |
这也是 http.HandleFunc 能直接接收普通函数的原因。
(3)http.ServeMux(路由多路复用器)
负责将不同的 URL 路径映射到对应的处理器,默认的 DefaultServeMux 是一个全局的 ServeMux 实例。
核心方法:
方法 | 作用 |
NewServeMux() *ServeMux | 创建一个新的路由多路复用器(推荐自定义,避免全局冲突) |
mux.Handle(pattern string, handler Handler) | 注册路径与处理器的映射 |
mux.HandleFunc(pattern string, fn func(ResponseWriter, *Request)) | 简化版,直接注册函数处理器 |
mux.ServeHTTP(w ResponseWriter, r *Request) | 实现 Handler 接口,分发请求到对应处理器 |
自定义 ServeMux 示例:
Go func main() { // 创建自定义路由 mux := http.NewServeMux() mux.HandleFunc("/", helloHandler) mux.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("User Page")) })
// 启动服务时指定自定义 mux http.ListenAndServe(":8080", mux) } |
(4)http.Server(自定义服务器配置)
ListenAndServe 是封装后的简化方法,若需自定义超时、TLS、地址等,可直接使用 http.Server:
核心字段与方法:
Go // 核心字段 type Server struct { Addr string // 监听地址(如 ":8080") Handler Handler // 路由处理器(默认 DefaultServeMux) ReadTimeout time.Duration // 读取请求的超时时间 WriteTimeout time.Duration // 写入响应的超时时间 MaxHeaderBytes int // 请求头最大字节数 // 其他字段:TLSConfig、IdleTimeout 等 }
// 核心方法 func (s *Server) ListenAndServe() error // 启动 HTTP 服务 func (s *Server) ListenAndServeTLS(certFile, keyFile string) error // 启动 HTTPS 服务 func (s *Server) Shutdown(ctx context.Context) error // 优雅关闭服务(不中断现有请求) |
自定义 Server 示例:
Go func main() { mux := http.NewServeMux() mux.HandleFunc("/", helloHandler)
// 配置自定义服务器 server := &http.Server{ Addr: ":8080", Handler: mux, ReadTimeout: 10 * time.Second, // 读取超时 10 秒 WriteTimeout: 10 * time.Second, // 写入超时 10 秒 MaxHeaderBytes: 1 << 20, // 最大请求头 1MB }
fmt.Println("Custom server starting on :8080...") err := server.ListenAndServe() if err != nil && err != http.ErrServerClosed { fmt.Printf("Server failed: %v\n", err) } } |
(5)http.ResponseWriter(响应写入器)
用于向客户端发送响应,核心方法:
方法 | 作用 |
Write([]byte) (int, error) | 向响应体写入字节数据(自动设置 Content-Type 为 text/plain) |
WriteHeader(int) | 设置 HTTP 响应状态码(如 404、500),必须在 Write 之前调用 |
Header() Header | 获取响应头映射,用于设置自定义响应头(如 Content-Type、Cookie) |
示例:
Go func handler(w http.ResponseWriter, r *http.Request) { // 设置响应头 w.Header().Set("Content-Type", "application/json; charset=utf-8") // 设置状态码 w.WriteHeader(http.StatusCreated) // 201 // 写入响应体 w.Write([]byte(`{"code":200,"msg":"success"}`)) } |
(6)http.Request(请求对象)
封装了客户端的 HTTP 请求信息,核心字段/方法:
字段/方法 | 作用 |
r.Method | 请求方法(GET/POST/PUT/DELETE 等) |
r.URL | 请求 URL(包含 Path、Query 参数等) |
r.Header | 请求头映射 |
r.Body | 请求体(io.ReadCloser 类型,需手动关闭) |
r.FormValue(key string) | 获取 Form/Query 参数(自动解析,优先 PostForm) |
r.PostFormValue(key string) | 仅获取 POST 表单参数 |
r.Cookies() | 获取所有 Cookie |
r.RemoteAddr | 客户端地址 |
r.ParseForm() error | 手动解析 Form 数据(FormValue 会自动调用) |
示例:
Go func formHandler(w http.ResponseWriter, r *http.Request) { // 解析表单(POST 需手动调用,GET 自动) err := r.ParseForm() if err != nil { http.Error(w, "解析表单失败", http.StatusBadRequest) return }
// 获取 Query 参数 name := r.FormValue("name") // 获取 POST 表单参数 age := r.PostFormValue("age")
fmt.Fprintf(w, "Name: %s, Age: %s", name, age) } |
三、客户端:发送 HTTP 请求
net/http 也提供了完整的 HTTP 客户端能力,核心是 http.Client 类型。
1. 最简请求(封装方法)
http 包提供了直接发送 GET/POST 等请求的快捷方法:
(1)http.Get(url string) (*Response, error)
发送 GET 请求:
Go func main() { // 发送 GET 请求 resp, err := http.Get("https://httpbin.org/get") if err != nil { fmt.Printf("Get failed: %v\n", err) return } defer resp.Body.Close() // 必须关闭响应体,避免内存泄漏
// 读取响应体 body, err := io.ReadAll(resp.Body) if err != nil { fmt.Printf("Read body failed: %v\n", err) return }
fmt.Printf("Status: %s\nBody: %s\n", resp.Status, string(body)) } |
(2)http.Post(url, contentType string, body io.Reader) (*Response, error)
发送 POST 请求:
Go func main() { // 构造 POST 表单数据 data := url.Values{} data.Set("name", "go") data.Set("age", "10")
// 发送 POST 请求(contentType 为 application/x-www-form-urlencoded) resp, err := http.Post("https://httpbin.org/post", "application/x-www-form-urlencoded", strings.NewReader(data.Encode())) if err != nil { fmt.Printf("Post failed: %v\n", err) return } defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body) fmt.Println(string(body)) } |
(3)http.PostForm(url string, data url.Values) (*Response, error)
简化版 POST 表单请求(自动设置 contentType):
Go resp, err := http.PostForm("https://httpbin.org/post", url.Values{"name": {"go"}, "age": {"10"}}) |
(4)http.Head(url string) (*Response, error)
发送 HEAD 请求(仅返回响应头,无响应体):
Go resp, err := http.Head("https://httpbin.org/get") fmt.Println(resp.Status) // 打印状态码 fmt.Println(resp.Header) // 打印响应头 |
2. 自定义客户端(http.Client)
快捷方法使用的是全局默认客户端 http.DefaultClient,自定义客户端可配置超时、代理、Cookie 等:
Go func main() { // 自定义客户端配置 client := &http.Client{ Timeout: 10 * time.Second, // 请求超时 10 秒 // Transport: &http.Transport{ // 自定义传输层(代理、TLS 等) // Proxy: http.ProxyFromEnvironment, // TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // 跳过 HTTPS 证书验证(测试用) // }, }
// 构造自定义请求(支持设置请求头、Method 等) req, err := http.NewRequest("PUT", "https://httpbin.org/put", strings.NewReader(`{"key":"value"}`)) if err != nil { fmt.Printf("Create request failed: %v\n", err) return }
// 设置请求头 req.Header.Set("Content-Type", "application/json") req.Header.Set("User-Agent", "Go-Client/1.0")
// 发送请求 resp, err := client.Do(req) if err != nil { fmt.Printf("Do request failed: %v\n", err) return } defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body) fmt.Println(string(body)) } |
http.Client 核心方法:
方法 | 作用 |
client.Do(req *Request) (*Response, error) | 发送自定义请求(最核心,支持所有 HTTP 方法) |
client.Get(url string) (*Response, error) | 封装的 GET 请求(内部调用 Do) |
client.Post(url, contentType string, body io.Reader) (*Response, error) | 封装的 POST 请求 |
client.PostForm(url string, data url.Values) (*Response, error) | 封装的表单 POST 请求 |
3. http.Response(客户端响应对象)
客户端接收到的响应,核心字段/方法:
字段/方法 | 作用 |
resp.Status | 响应状态(如 "200 OK") |
resp.StatusCode | 响应状态码(如 200、404) |
resp.Header | 响应头映射 |
resp.Body | 响应体(io.ReadCloser 类型,必须关闭) |
resp.Cookies() | 获取响应中的 Cookie |
四、其他常用工具方法
方法 | 作用 |
http.Error(w ResponseWriter, error string, code int) | 快速返回错误响应(自动设置状态码和响应体) |
http.Redirect(w ResponseWriter, r *Request, url string, code int) | 重定向(常用 301/302) |
http.SetCookie(w ResponseWriter, cookie *Cookie) | 向响应中添加 Cookie |
http.DetectContentType(data []byte) string | 检测数据的 Content-Type(如 text/html、application/json) |
示例:
Go // 快速返回 404 错误 func notFoundHandler(w http.ResponseWriter, r *http.Request) { http.Error(w, "Page Not Found", http.StatusNotFound) }
// 重定向 func redirectHandler(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "https://www.google.com", http.StatusTemporaryRedirect) }
// 设置 Cookie func cookieHandler(w http.ResponseWriter, r *http.Request) { cookie := &http.Cookie{ Name: "token", Value: "123456", Path: "/", MaxAge: 3600, // 有效期 1 小时 } http.SetCookie(w, cookie) w.Write([]byte("Cookie set!")) } |
总结
- net/http 包核心分为服务器端和客户端两大能力:服务器端通过 Handler/ServeMux/Server 搭建服务,客户端通过 Client/Request/Response 发送请求。
- 服务器端核心是 Handler 接口,所有处理器都需实现它;HandlerFunc 是函数适配器,简化普通函数作为处理器的流程。
- 客户端开发中,简单场景用 http.Get/Post 等快捷方法,复杂场景(超时、代理、自定义头)用 http.Client + http.NewRequest 实现,且必须关闭 resp.Body 避免资源泄漏。
掌握这些核心类型和方法,就能覆盖大部分 HTTP 开发场景,进阶可结合中间件(如日志、鉴权)、路由框架(如 gin)扩展能力。
|(注:文档部分内容可能由 AI 生成)