在 Go HTTP 服务器中,自定义 Handler 返回特定状态码需先调用 ResponseWriter.WriteHeader() 再写入响应体;若未调用则默认 200 OK;重复调用无效;推荐封装错误响应或使用带 error 返回的 HandlerFunc 统一处理,避免依赖 http.Error 的局限性。
在 Go 的 HTTP 服务器中,自定义 Handler 返回特定状态码的关键,是直接调用 ResponseWriter.WriteHeader(),再写入响应体。注意:一旦调用 WriteHeader 或已向 ResponseWriter 写入数据(哪怕只写一个字节),状态码就无法再修改。
这是最直接、最标准的方式。必须在调用 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")
可定义带错误返回的函数类型,配合中间件或包装器集中处理:
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(w, msg, status) 是便捷方法,但它会自动设置 Content-Type: text/plain; charset=utf-8,且不支持自定义 header 或结构化响应(如 JSON)。生产环境建议自行控制 WriteHeader + Write,更灵活可靠。