在 Go HTTP 服务器中,自定义 Handler 返回特定状态码需先调用 ResponseWriter.WriteHeader() 再写入响应体;若未调用则默认 200 OK;重复调用无效;推荐封装错误响应或使用带 error 返回的 HandlerFunc 统一处理,避免依赖 http.Error 的局限性。

在 Go 的 HTTP 服务器中,自定义 Handler 返回特定状态码的关键,是直接调用 ResponseWriter.WriteHeader(),再写入响应体。注意:一旦调用 WriteHeader 或已向 ResponseWriter 写入数据(哪怕只写一个字节),状态码就无法再修改。
使用 http.ResponseWriter.WriteHeader() 显式设置状态码
这是最直接、最标准的方式。必须在调用 w.Write() 之前调用 w.WriteHeader(statusCode),否则 Go 会默认写入 200 OK。
- 如果未调用
WriteHeader就调用w.Write([]byte{...}),Go 自动发送200 - 如果先调用
w.WriteHeader(404),再调用w.Write([]byte{"not found"}),客户端收到的就是404 Not Found - 重复调用
WriteHeader无效(仅第一次生效)
封装错误响应逻辑避免重复代码
为提升可维护性,建议封装常用错误响应,例如:
func writeError(w http.ResponseWriter, status int, msg string) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(status)
json.NewEncoder(w).Encode(map[string]string{"error": msg})
}
然后在 handler 中按需调用:writeError(w, http.StatusUnauthorized, "token expired")writeError(w, http.StatusBadRequest, "invalid request body")
结合自定义 Handler 类型统一错误处理
可定义带错误返回的函数类型,配合中间件或包装器集中处理:
立即学习“go语言免费学习笔记(深入)”;
type HandlerFunc func(http.ResponseWriter, *http.Request) error
func (f HandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if err := f(w, r); err != nil {
switch {
case errors.Is(err, ErrNotFound):
http.Error(w, "not found", http.StatusNotFound)
case errors.Is(err, ErrUnauthorized):
http.Error(w, "unauthorized", http.StatusUnauthorized)
default:
http.Error(w, "internal error", http.StatusInternalServerError)
}
return
}
}
这样业务 handler 只需关注逻辑,错误由统一入口转换为对应状态码。
注意 http.Error 的局限性
http.Error(w, msg, status) 是便捷方法,但它会自动设置 Content-Type: text/plain; charset=utf-8,且不支持自定义 header 或结构化响应(如 JSON)。生产环境建议自行控制 WriteHeader + Write,更灵活可靠。










