HTTP错误响应必须封装成结构体,统一包含status_code、message、error_code字段;禁用http.Error,需显式设置Content-Type和状态码;用中间件recover panic并AbortWithStatusJSON;业务错误用自定义AppError类型区分状态码;鉴权错误须由中间件前置拦截并返回标准401/403。

HTTP错误响应必须封装成结构体,不能直接返回字符串或裸error
Go的http.Error虽然能快速返回错误,但会导致前端无法解析结构化数据。统一错误响应的核心是定义一个标准错误结构体,确保所有接口返回一致的status_code、message、error_code字段。
- 避免用
http.Error(w, "not found", http.StatusNotFound)——它只写入纯文本,Content-Type默认是text/plain,前端拿不到JSON字段 - 必须手动设置
w.Header().Set("Content-Type", "application/json; charset=utf-8") - 状态码要通过
w.WriteHeader(statusCode)显式设置,不能依赖json.Marshal自动设
用中间件拦截panic和未捕获error,避免服务崩溃
Web服务中未处理的panic会导致goroutine终止,但HTTP handler仍会返回500且无有效错误信息。中间件是兜底关键。
func Recovery() gin.HandlerFunc {
return func(c *gin.Context) {
defer func() {
if err := recover(); err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, map[string]interface{}{
"error_code": "INTERNAL_ERROR",
"message": "server error",
"status_code": http.StatusInternalServerError,
})
}
}()
c.Next()
}
}
- 使用
defer + recover()捕获panic,但注意:仅对当前goroutine生效,不跨goroutine传播 - 不要在recover里调用
c.JSON()后继续c.Next()——必须用c.AbortWithStatusJSON()中断流程 - 若用原生
net/http,需包装http.Handler,类似http.HandlerFunc闭包模式
业务错误要用自定义error类型区分,而非全用fmt.Errorf
统一响应需要识别错误类型来映射HTTP状态码和错误码,比如ErrNotFound应返回404,ErrInvalidParam应返回400。
将一个或多个 UI 原型图、线框图、产品截图或设计稿转换为标准化、可直接交付的 PRD 风格文档,供产品、设计、前端和测试共同使用。适用于 Codex 需要分析 PC 网页、桌面端、移动端、响应式页面、独立弹窗、表单、表格、看板、数据大屏或多页面流程截图,还原页面结构与交互,强制套用固定文档模板,抽取跨页面共享规则,或把一组原型沉淀为单页规范文档加整体业务流程文档的场景。不适用于纯视觉审美点评、代码实现、接口设计、埋点方案、竞品分析或无 UI 输入的业务需求创作。
type AppError struct {
Code string
Message string
Status int
}
func (e *AppError) Error() string { return e.Message }
var (
ErrNotFound = &AppError{"NOT_FOUND", "resource not found", http.StatusNotFound}
ErrInvalidParam = &AppError{"INVALID_PARAM", "invalid request parameter", http.StatusBadRequest}
)
- 不要用
errors.Is(err, ErrNotFound)做深层判断——如果错误被fmt.Errorf("failed: %w", err)包装过,errors.Is仍能穿透识别 - 在handler中用
switch或errors.As提取*AppError,再决定返回什么HTTP状态和JSON结构 - 数据库层(如
gorm)的record not found错误需主动转为ErrNotFound,不能透传原始error
HTTP 401/403等认证鉴权错误必须由中间件提前拦截
权限校验失败不能等到业务逻辑里才返回错误,否则可能已执行副作用(如扣款、发消息)。Auth中间件应在c.Next()前就决策是否放行。
立即学习“go语言免费学习笔记(深入)”;
- JWT解析失败、token过期、scope不足等,应统一返回
401 Unauthorized或403 Forbidden,并带明确error_code(如"TOKEN_EXPIRED") - 不要在每个handler里重复写
if !authorized { ... }——抽取为AuthRequired()中间件 - 注意:401响应必须带
WWW-Authenticate头(如w.Header().Set("WWW-Authenticate", "Bearer")),否则部分客户端(如curl -v)无法识别认证失败语义
Error方法只是快捷封装,真正可控的错误流必须自己管理error类型、状态码映射和响应格式。最容易被忽略的是:**HTTP状态码和JSON body里的status_code字段必须保持一致,且不能靠客户端自行推断**——后者会导致前端异常处理分支错乱。

















