Files
cs-note/hhs/GIN/6-error-handling/q-biz-code-header.md
T
2026-05-24 11:42:38 +08:00

2.6 KiB
Raw Blame History

tags, create time
tags create time
后端
Go
Gin
错误处理
API设计
2026-04-28 00:15

业务错误码:JSON Body vs 响应头

概述

讨论 API 返回业务错误码时,应该放在 JSON body 还是自定义 HTTP 响应头(如 X-Biz-Code),以及何时需要两者兼有。

正文

方案对比

JSON Body(code 字段) 响应头(X-Biz-Code)
优点 解析简单,所有语言/框架天然支持 中间件/网关不经解析 body 就能识别错误类型
缺点 客户端必须先解析 body 才知道发生了什么 不是所有代理层都透传自定义头;某些 SDK 默认不暴露 headers
// 方案 A:仅 JSON body
c.JSON(http.StatusBadRequest, gin.H{
    "code":    40001,
    "message": "参数校验失败",
})

// 方案 B:同时写入 header + body
c.Header("X-Biz-Code", strconv.Itoa(40001))
c.JSON(http.StatusBadRequest, gin.H{
    "code":    40001,
    "message": "参数校验失败",
})

面向前端(同团队)

JSON body 就够了。前端代码是你写的,统一走 body 的 code 字段即可,加 header 反而增加复杂度。

// 前端统一拦截器处理
axios.interceptors.response.use(null, (err) => {
    const bizCode = err.response?.data?.code;
    if (bizCode === 40001) showToast("请检查输入");
    if (bizCode === 40101) navigateTo("/login");
    return Promise.reject(err);
});

面向第三方开发者 —— 推荐双通道

原因有三:

  1. 网关 / 反向代理决策——WAF、API Gateway 或熔断器通常只能看 HTTP 状态码和 header,无法解析 JSON body。X-Biz-Code 能让网关直接拦截特定错误(比如 40001 直接限流,而不打到你的服务)。

  2. SDK 封装友好——第三方集成 SDK 后,可根据 header 快速区分重试策略:瞬时错误自动重试,确定错误直接抛出,无需先解 body。

  3. 调试效率——运维通过日志打印 $http_x_biz_code 就能一眼看到业务错误分布,不用额外解析请求体。

Gin 中的统一实现

func handleBizError(c *gin.Context, httpCode, bizCode int, msg string) {
    c.Header("X-Biz-Code", strconv.Itoa(bizCode)) // ← header
    c.JSON(httpCode, gin.H{                        // ← body
        "code":    bizCode,
        "message": msg,
    })
}

成本极小——多一行 c.Header() 而已,但对两边的使用者(前端 + 第三方)都照顾到了。

关联笔记