后端常见错误码总结

按 HTTP 状态码和业务错误码两个层次,总结后端接口常见错误码的含义、触发场景和处理建议。

后端后端错误码HTTPAPI设计

后端错误码通常分为两层:一层是 HTTP 状态码,用来表达请求在协议层面的处理结果;另一层是业务错误码,用来表达具体业务规则失败的原因。

一个可维护的接口错误设计,应该做到三件事:HTTP 状态码语义正确,业务错误码稳定可检索,错误信息对前端和排查问题都有帮助。

一、HTTP 状态码

HTTP 状态码描述的是“这次请求在 Web 协议层面发生了什么”。它不应该承载过细的业务含义,而应该告诉调用方请求是否成功、是否需要重新登录、是否没有权限、是否请求参数错误,或者服务端是否异常。

1xx:信息响应

这类状态码在日常业务接口中不常直接处理,更多由 HTTP 协议、网关或底层框架完成。

状态码含义常见场景
100 Continue请求头已接收,客户端可以继续发送请求体大文件上传前的预确认
101 Switching Protocols协议切换HTTP 升级到 WebSocket

2xx:请求成功

2xx 表示请求已被服务端成功接收、理解并处理。

状态码含义常见场景
200 OK请求成功查询、普通提交、修改成功
201 Created创建成功新增用户、创建订单、上传资源成功
202 Accepted已接受但未处理完成异步任务、导出任务、消息投递
204 No Content成功但无响应体删除成功、只需要返回成功状态的更新操作

实际接口中最常见的是 200。如果想让 REST 语义更清晰,可以在创建资源时返回 201,在删除成功且不需要正文时返回 204

3xx:重定向

3xx 表示客户端需要进一步操作才能完成请求。后端 API 中不算高频,但在登录跳转、资源迁移、文件下载地址重定向中会遇到。

状态码含义常见场景
301 Moved Permanently永久重定向老接口或老域名永久迁移
302 Found临时重定向登录页跳转、临时下载地址
304 Not Modified资源未变化浏览器缓存、静态资源缓存
307 Temporary Redirect临时重定向,保持原请求方法保留 POST 方法的临时跳转
308 Permanent Redirect永久重定向,保持原请求方法保留请求方法的永久迁移

对前后端分离接口来说,未登录时一般不建议直接返回 302 跳登录页,更推荐返回 401,由前端决定跳转逻辑。

4xx:客户端错误

4xx 表示请求本身存在问题,或者当前调用方没有完成这次请求的条件。

状态码含义常见场景
400 Bad Request请求格式或参数错误JSON 格式错误、参数类型不对、缺少必填字段
401 Unauthorized未认证未登录、Token 缺失、Token 过期
403 Forbidden已认证但无权限普通用户访问管理员接口、权限不足
404 Not Found资源不存在用户不存在、订单不存在、接口路径不存在
405 Method Not Allowed请求方法不允许GET 调用了只支持 POST 的接口
409 Conflict资源冲突重复创建、版本冲突、状态已变更
410 Gone资源已永久删除老资源被下线且不再恢复
413 Payload Too Large请求体过大上传文件超过限制
415 Unsupported Media Type媒体类型不支持接口要求 JSON,却传了表单或错误的 Content-Type
422 Unprocessable Entity参数语义校验失败格式正确,但业务校验不通过
429 Too Many Requests请求过于频繁限流、验证码频繁发送、登录尝试过多

400422 的区别容易混淆。简单理解:请求结构都不合法时用 400;结构合法,但字段值不符合业务规则时可用 422。如果团队不想区分这么细,也可以统一用 400,但业务错误码要足够清楚。

401403 也要分清楚:401 是“你是谁还没确认”,403 是“知道你是谁,但你不能做这件事”。

5xx:服务端错误

5xx 表示服务端处理请求时出现异常,调用方通常无法通过修改请求参数直接解决。

状态码含义常见场景
500 Internal Server Error服务端内部错误未捕获异常、空指针、代码缺陷
501 Not Implemented功能未实现路由存在但方法未完成
502 Bad Gateway网关收到上游无效响应Nginx、API 网关调用后端失败
503 Service Unavailable服务暂不可用服务维护、依赖不可用、实例过载
504 Gateway Timeout网关等待上游超时后端响应太慢、依赖超时

线上接口应尽量避免把底层异常、SQL、堆栈信息直接返回给客户端。客户端只需要稳定的错误码和可理解的信息,详细原因应该进入日志和链路追踪系统。

二、业务错误码

HTTP 状态码只能表达大方向,业务错误码才适合表达具体失败原因。例如同样是 400,可能是手机号格式错误、验证码错误、库存不足,也可能是订单状态不允许取消。

常见响应结构可以设计成这样:

{
  "code": "USER_NOT_FOUND",
  "message": "用户不存在",
  "requestId": "req_20260622103000123",
  "data": null
}

也可以使用数字编码:

{
  "code": 100404,
  "message": "用户不存在",
  "requestId": "req_20260622103000123",
  "data": null
}

字符串错误码可读性更好,适合跨团队协作和日志检索;数字错误码更短,适合已有编码规范的系统。无论选择哪一种,关键是稳定、唯一、可文档化。

常见业务错误码分类

分类示例错误码含义建议 HTTP 状态码
通用错误UNKNOWN_ERROR未知错误500
通用错误PARAM_INVALID参数不合法400422
通用错误PARAM_MISSING缺少必填参数400
通用错误REQUEST_TOO_FREQUENT请求过于频繁429
认证授权UNAUTHORIZED未登录或 Token 无效401
认证授权TOKEN_EXPIREDToken 已过期401
认证授权FORBIDDEN无访问权限403
用户模块USER_NOT_FOUND用户不存在404
用户模块USER_DISABLED用户被禁用403
用户模块PASSWORD_INCORRECT密码错误400401
验证码CAPTCHA_INVALID验证码错误400
验证码CAPTCHA_EXPIRED验证码已过期400
订单模块ORDER_NOT_FOUND订单不存在404
订单模块ORDER_STATUS_INVALID当前订单状态不允许操作409
支付模块PAYMENT_FAILED支付失败400502
支付模块PAYMENT_TIMEOUT支付超时504
库存模块STOCK_NOT_ENOUGH库存不足409
文件模块FILE_TOO_LARGE文件过大413
文件模块FILE_TYPE_UNSUPPORTED文件类型不支持415
外部依赖UPSTREAM_UNAVAILABLE上游服务不可用503
外部依赖UPSTREAM_TIMEOUT上游服务超时504

业务错误码不要设计成只给机器看的编号,也不要让同一个错误码在不同场景下表达不同含义。错误码一旦被前端、客户端、第三方系统依赖,就应该像接口字段一样谨慎变更。

三、错误码设计建议

1. HTTP 状态码不要全部返回 200

有些系统会把所有响应都包装成 200 OK,然后只依赖业务 code 判断成功或失败:

{
  "code": 401001,
  "message": "Token 已过期"
}

这种方式实现简单,但会削弱网关、监控、缓存、客户端 SDK 对 HTTP 语义的利用。更推荐的做法是:

HTTP/1.1 401 Unauthorized
Content-Type: application/json

{
  "code": "TOKEN_EXPIRED",
  "message": "登录状态已过期,请重新登录"
}

这样协议层和业务层各司其职,排查问题也更直观。

2. 错误信息分为用户信息和排查信息

返回给用户的 message 应该清楚、克制,不暴露内部实现:

{
  "code": "ORDER_STATUS_INVALID",
  "message": "当前订单状态不支持取消",
  "requestId": "req_20260622103000123"
}

日志里则应该记录更完整的排查信息,例如用户 ID、订单 ID、接口路径、堆栈、依赖耗时等。

不要把下面这些内容直接返回给客户端:

SQL 语句
数据库表名和字段名
服务器绝对路径
异常堆栈
密钥、Token、手机号、身份证号等敏感信息

3. 错误码要有命名规则

字符串错误码可以采用模块前缀:

AUTH_TOKEN_EXPIRED
USER_NOT_FOUND
ORDER_STATUS_INVALID
PAYMENT_TIMEOUT

数字错误码可以采用分段规则:

100000-199999 通用错误
200000-299999 用户与认证
300000-399999 订单
400000-499999 支付
500000-599999 文件与资源
900000-999999 系统与外部依赖

不要今天返回 USER_NOT_FOUND,明天改成 USER_NOT_EXISTS。错误码名称可以不完美,但必须稳定。

4. 同一类错误保持一致

同样的错误在不同接口中应该返回同样的结构。例如用户不存在,不要在 A 接口返回:

{
  "code": "USER_NOT_FOUND",
  "message": "用户不存在"
}

在 B 接口又返回:

{
  "errorCode": 40401,
  "errorMsg": "查无此用户"
}

统一结构可以降低前端判断成本,也方便日志聚合、告警和接口文档维护。

5. 给每次错误响应带上 requestId

生产环境排查问题时,requestId 很重要。用户或前端只要提供这个 ID,后端就可以在日志、链路追踪、网关记录中定位到对应请求。

推荐结构:

{
  "code": "UPSTREAM_TIMEOUT",
  "message": "服务响应超时,请稍后重试",
  "requestId": "req_20260622103000123"
}

四、常用速查表

场景HTTP 状态码业务错误码示例
请求成功200OK
创建成功201CREATED
删除成功且无返回体204无需响应体
参数格式错误400PARAM_INVALID
未登录401UNAUTHORIZED
Token 过期401TOKEN_EXPIRED
无权限403FORBIDDEN
资源不存在404RESOURCE_NOT_FOUND
请求方法错误405METHOD_NOT_ALLOWED
资源状态冲突409RESOURCE_CONFLICT
文件过大413FILE_TOO_LARGE
媒体类型不支持415FILE_TYPE_UNSUPPORTED
参数语义校验失败422VALIDATION_FAILED
请求过于频繁429REQUEST_TOO_FREQUENT
服务端异常500INTERNAL_ERROR
上游服务异常502UPSTREAM_BAD_RESPONSE
服务不可用503SERVICE_UNAVAILABLE
上游超时504UPSTREAM_TIMEOUT