

新闻资讯
技术学院应统一错误响应结构为含code、message、request_id的APIError,禁用http.Error;通过中间件+context透传request_id;panic时recover并走统一错误流程,同时校验ctx.Err()防止二次panic。
直接用 http.Error 或裸写 JSON 会导致前端难解析、日志难聚合、错误码不一致。建议所有公共 API 的错误响应都走同一结构体,且必须包含 code(业务码)、message(用户提示)、request_id(用于排查)。
常见错误是把 error 值直接序列化进 JSON,结果出现 "error": "EOF" 这类不可读内容;或漏掉 Content-Type: application/json 导致前端解析失败。
type APIError struct {
Code int `json:"code"`
Message string `json:"message"`
RequestID string `json:"request_id,omitempty"`
}WriteJSON 方法中统一处理:遇到 error 类型时,自动转成 APIError 并设状态码(如 400 对应参数错误,500 对应未预期错误)http.Error;它不支持自定义字段,且默认 Content-Type 是 text/plain
前端需要根据 code 做不同动作(比如重试、跳登录页、弹提示),所以不能全塞 500 或只用 errors.New 包裹字符串。
推荐用带类型标签的错误,比如用 fmt.Errorf("invalid token: %w", err) + 自定义错误类型实现 Is 和 Unwrap,再在响应层映射到对应 code:
ErrValidation → code: 400(参数校验失败)ErrUnauthorized → code: 401(token 过期/无效)ErrNotFound → code: 404(资源不存在)ErrInternal → code: 500(服务端 panic 或 DB 超时等)避免把数据库错误(如 "pq: duplicate key violates unique constraint")直接透出给前端——这类信息要被拦截并转为更友好的 message,同时记录完整原始 error 到日志。
没有 request_id,线上报错时根本没法对齐日志。它必须在入口(如 http.ServeHTTP 第一行)就生成,并贯穿整个请求生命周期。
uuid.NewString() 或 rand.String(12) 生成,不要用时间戳或递增 ID(并发不安全、易猜测)context.Context,后续所有日志、DB 查询、下游调用都要带上它X-Request-ID,响应体 JSON 里也放一份 request_id 字段,方便前端上报问题时提供上下文X-Request-ID 中间件——确认它是否真会写入响应体;很多只写 header 不写 bodyGo HTTP server 遇到 panic 默认会返回 500 Internal Server Error 和空 body,前端收不到 code 和 request_id,监控也抓不到上下文。
必须用 recover() 拦住 panic,并强制走统一错误响应流程:
middleware 里 defer recover,捕获后调用统一错误写入函数debug.PrintStack() 或 runtime/debug.Stack()),但绝不返回给前端go fn()),需各自加 recover最容易被忽略的是 context 超时或取消后继续写响应——recover 之后还得检查 ctx.Err() != nil,否则可能 panic 恢复了,但连接已断,再写 JSON 会 panic 二次。