Go 的 net/http 包轻量可控但裸用易导致维护难、错误处理不统一、缺乏中间件和参数化路由;推荐新项目直接使用 chi 等第三方路由器,并手动控制 RESTful 方法、状态码、JSON 序列化及中间件链。

Go 的 net/http 包足够轻量且可控,适合构建生产级 RESTful 接口,但直接裸用容易写出难以维护、缺乏统一错误处理和中间件能力的代码。
用 http.ServeMux 做基础路由时,路径匹配不支持参数提取
默认的 http.ServeMux 只支持前缀匹配(如 /api/users/),无法像 /api/users/{id} 这样提取路径段。硬编码拼接或手动 strings.Split(r.URL.Path, "/") 容易出错,且无法区分 /api/users 和 /api/users/123 的语义。
- 改用第三方路由器(如
gorilla/mux或chi)是更稳妥的选择 - 若坚持原生方案,可封装一个简单路径解析函数,但需自行处理边界情况(如空段、重复斜杠)
-
chi的chi.Router支持r.Get("/users/{id}", handler),且内置中间件链,推荐新项目直接使用
RESTful 方法与状态码必须显式控制,Go 不会自动推断
HTTP 方法(GET/POST/PUT/DELETE)和响应状态码(200/201/404/400)全靠开发者在 http.HandlerFunc 中手动设置,没有框架层的语义约束。
- 务必在每个 handler 开头校验
r.Method,未支持的方法返回http.StatusMethodNotAllowed - 创建资源用
http.StatusCreated(201),并设置Locationheader 指向新资源地址 - 错误响应建议统一结构(如
{"error": "user not found"}),避免混用字符串、nil或 panic
func createUser(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
// ... 解析 JSON
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(map[string]string{"id": "123"})
}
JSON 序列化默认忽略零值字段,但 API 通常需要显式返回 null 或空数组
Go 结构体字段若为指针或带 omitempty 标签,在值为零值(0、""、nil)时会被 json.Marshal 跳过,导致前端无法区分“字段不存在”和“字段为零值”。
立即学习“go语言免费学习笔记(深入)”;
- 去掉
omitempty,改用指针类型(如*string)表示可选字段 - 对布尔字段慎用
omitempty:前端常需明确知道is_active: false是有意设置,而非缺失 - 若需兼容旧客户端,可定义两个结构体:一个用于接收(含
omitempty),一个用于响应(无omitempty)
中间件必须手动链式调用,没有自动注册机制
net/http 的中间件本质是嵌套的 http.Handler,需显式包装,比如日志、鉴权、CORS 都得一层层套进去,写法冗长且易漏掉 next.ServeHTTP。
- 用闭包封装中间件逻辑,例如
func logging(next http.Handler) http.Handler - 用
chi时可直接r.Use(middleware.Logger),内部已实现链式调度 - 注意中间件顺序:鉴权应在业务 handler 之前,而 CORS 头一般放在最外层
func authMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
if token == "" {
http.Error(w, "unauthorized", http.StatusUnauthorized)
return
}
// ... 验证 token
next.ServeHTTP(w, r)
})
}
裸用 net/http 的最大成本不在写接口,而在补全错误处理、参数校验、日志、超时、重试这些非功能性需求;一旦项目规模超过 5 个 endpoint,就该考虑 chi 或 gin 这类轻量框架——它们不绑架你,但省下大量胶水代码。










