Go 语言的标准库 net/http 提供了强大的 HTTP 客户端和服务端实现,是构建 Web 应用和 API 的基础。本文将从零开始,带你全面掌握 net/http 包的使用,包括服务端搭建、请求处理、路由匹配、参数获取、最佳实践等内容,并重点介绍 Go 1.22 带来的路由增强特性。
一、HTTP 服务端基础
1.1 最简单的 HTTP 服务器
go
package main
import (
"fmt"
"net/http"
)
func helloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, World!")
}
func main() {
http.HandleFunc("/", helloHandler)
http.ListenAndServe(":8080", nil)
}
1.2 核心接口:http.Handler
任何实现了 ServeHTTP(ResponseWriter, *Request) 方法的类型都可以作为 HTTP 处理器。
go
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
1.3 服务启动的两种方式
✅ 使用默认路由(包级别函数)
go
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
✅ 自定义 Server 实例(推荐生产环境)
go
s := &http.Server{
Addr: ":8080",
Handler: myHandler,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
log.Fatal(s.ListenAndServe())
1.4 支持 HTTPS
go
http.ListenAndServeTLS(":443", "server.crt", "server.key", nil)
二、请求与响应处理
2.1 核心对象
http.ResponseWriter:构造响应*http.Request:获取请求信息
2.2 构建响应示例
go
func handler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
w.Write([]byte(`{"status": "success"}`))
}
2.3 读取请求信息
go
method := r.Method
path := r.URL.Path
userAgent := r.Header.Get("User-Agent")
ip := r.RemoteAddr
三、路由与路径匹配
3.1 基础路由注册
go
http.HandleFunc("/", homeHandler)
http.HandleFunc("/users", usersHandler)
3.2 自定义 ServeMux
go
mux := http.NewServeMux()
mux.HandleFunc("/", homeHandler)
http.ListenAndServe(":8080", mux)
3.3 Go 1.22+ 路由增强
✅ 方法匹配
go
http.HandleFunc("GET /posts/{id}", handleGetPost)
http.HandleFunc("POST /posts", handleCreatePost)
✅ 路径通配符
go
http.HandleFunc("GET /posts/{id}", func(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
fmt.Fprintf(w, "Post ID: %s", id)
})
✅ 剩余路径匹配
go
http.HandleFunc("GET /files/{path...}", func(w http.ResponseWriter, r *http.Request) {
path := r.PathValue("path")
fmt.Fprintf(w, "File path: %s", path)
})
3.4 路由优先级规则
- 最具体模式获胜(Go 1.22+)
- 传统规则:长路径优先
四、请求方法处理
4.1 方法判断
go
switch r.Method {
case http.MethodGet:
handleGet(w, r)
case http.MethodPost:
handlePost(w, r)
}
4.2 Go 1.22+ 方法限定
go
mux.HandleFunc("GET /users", listUsers)
mux.HandleFunc("POST /users", createUser)
4.3 第三方路由库(gorilla/mux)
go
r := mux.NewRouter()
r.HandleFunc("/products/{id:[0-9]+}", productHandler)
五、请求参数处理
| 参数类型 | 获取方式 | 示例 |
|---|---|---|
| 查询参数 | r.URL.Query().Get("key") |
/users?page=1 |
| 表单参数 | r.FormValue("key") |
username=john |
| 路径参数 | r.PathValue("id") |
/users/123 |
| JSON 请求体 | json.NewDecoder(r.Body).Decode |
{"name":"john"} |
| 原始请求体 | io.ReadAll(r.Body) |
二进制 / XML 等 |
JSON 解析示例
go
var user User
err := json.NewDecoder(r.Body).Decode(&user)
六、完整示例:RESTful API(Go 1.22+)
go
package main
import (
"encoding/json"
"net/http"
"strconv"
"sync"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Age int `json:"age"`
}
var (
users = make(map[int]User)
nextID = 1
usersMu sync.RWMutex
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("GET /users", listUsers)
mux.HandleFunc("POST /users", createUser)
mux.HandleFunc("GET /users/{id}", getUser)
mux.HandleFunc("PUT /users/{id}", updateUser)
mux.HandleFunc("DELETE /users/{id}", deleteUser)
http.ListenAndServe(":8080", mux)
}
// 各函数实现略(详见原文)
七、常见错误与最佳实践
❌ 常见错误
- 未关闭响应体
- 在写入响应体后调用
WriteHeader - 忽略错误处理
- 未设置超时
✅ 最佳实践
- 重用 HTTP 客户端
- 使用 Context 控制超时
- 统一响应格式
- 输入验证
- 优雅关闭服务器
优雅关闭示例
go
srv := &http.Server{Addr: ":8080", Handler: mux}
go srv.ListenAndServe()
<-quit
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
srv.Shutdown(ctx)
八、总结
| 组件 | 关键类型/函数 | 用途 |
|---|---|---|
| 服务端 | http.ListenAndServe、http.Server |
启动服务 |
| 处理器 | Handler 接口、HandleFunc |
处理请求 |
| 请求 | *http.Request |
获取请求信息 |
| 响应 | http.ResponseWriter |
构建响应 |
| 路由 | ServeMux、DefaultServeMux |
路由分发 |
| 参数 | URL.Query()、FormValue()、PathValue() |
获取请求参数 |
Go 1.22+ 亮点
- 方法匹配
- 路径通配符
- 最具体规则
学习建议
- 从标准库入手,理解
Handler接口 - 注意 Go 版本差异(1.22 路由增强)
- 实践时注重错误处理、超时控制、资源关闭