第 11 章

错误码与附录

统一响应结构、全局异常映射、认证失败特殊格式、业务错误码总索引,以及引擎 / 语言 / 枚举 / 配置项速查附录。

11.1 统一响应结构

除流式接口(SSE)、文件流(术语导出、文档下载)与支付回调直写响应外, 所有 /api/** 接口的返回体均由 ApiResponseAdvice 统一包装为以下结构:

成功响应(ApiResponse)
{
  "success": true,          // 业务是否成功,客户端首先判断此字段
  "message": "操作成功",      // 人读提示信息
  "data": { ... },          // 业务数据(各章节详述),可为 null
  "error": null              // 成功时为 null;失败时为错误码字符串或错误明细对象
}
失败响应(HTTP 状态码 + 同结构)
HTTP/1.1 402 Payment Required
{
  "success": false,
  "message": "点数不足,无法完成当前操作",
  "data": "点数余额与会员配额不足,无法完成本次翻译",   // data 承载具体原因
  "error": "INSUFFICIENT_POINTS"                        // error 承载机器可读错误码
}
分页响应(PagedResponse,多数列表接口的 data)
{
  "data": [ ... ],          // 当前页数据数组
  "page": 0,                // 页码,0 起始
  "size": 10,               // 每页条数
  "totalPages": 3,          // 总页数
  "totalElements": 25        // 总条数
}

⚠️ 例外:/api/moments/list 的 data 是自定义 {total, page, size, items} 结构(见 10.4), 对话历史等个别接口分页字段命名以各章描述为准。

11.2 全局异常处理器(GlobalExceptionHandler)

异常处理器以 @RestControllerAdvice(annotations = RestController.class) 声明, 只拦截 API 控制器(@RestController),页面控制器(@Controller)的异常走独立的错误页流程,不受本表影响。 映射关系如下(HTTP 状态码 → error 错误码):

异常类型HTTPerror 错误码message / data 说明
MethodArgumentNotValidException400VALIDATION_ERRORmessage=「参数验证失败」;data 为 {字段名: 错误提示} 明细 Map
BindException400BIND_ERRORmessage=「数据绑定失败」;data 同样为字段级错误 Map
MethodArgumentTypeMismatchException400TYPE_MISMATCHdata=「参数 '{name}' 的值 '{value}' 无法转换为 {类型}」
MaxUploadSizeExceededException413FILE_TOO_LARGEmessage=「文件上传大小超限」
IllegalArgumentException400ILLEGAL_ARGUMENTmessage=「非法参数」;data=异常原始消息(如「订单不存在」「分类不合法」)
IllegalStateException409ILLEGAL_STATEmessage=「非法状态」;data=异常原始消息(如「订单已过期」「操作繁忙,请稍后重试」)
InsufficientPointsException402INSUFFICIENT_POINTSmessage=「点数不足,无法完成当前操作」;data=具体不足原因(点数 / 会员配额分别说明)
NullPointerException500NULL_POINTERmessage=「系统内部错误」;data=固定提示语(不泄露堆栈)
RuntimeException500RUNTIME_ERRORmessage=「系统内部错误」;data=固定提示语
Exception(兜底)500INTERNAL_ERRORmessage=「系统内部错误」;data=「系统发生未知异常,请联系管理员」

💡 除上述统一映射外,个别控制器还有控制器内自行捕获的分支(优先于全局处理器生效): 如 /api/user/** 将 ResourceNotFoundException 捕获为 404 USER_NOT_FOUND, /api/moments/** 将业务异常捕获为 MOMENTS_LIST_FAILED / MOMENTS_CREATE_FAILED(见第 10 章)。

11.3 认证失败的特殊响应(401)

⚠️ 这是全系统唯一不走 ApiResponse 包装的 JSON 错误响应: 认证拦截器(AuthTokenInterceptor,见第 02 章)在 Token 缺失 / 过期 / 非法时直接写回原生 JSON:

拦截器 401 响应(非 ApiResponse 结构)
HTTP/1.1 401 Unauthorized
Content-Type: application/json

{ "code": 401, "message": "Missing token" }        // 未携带 Token
{ "code": 401, "message": "Token expired" }         // Token 已过期
{ "code": 401, "message": "Session expired" }       // 会话失效
{ "code": 401, "message": "Invalid token" }         // Token 非法

客户端解析错误响应时务必同时兼容两种结构:拦截器 401 用 code/message, 业务错误用 success/message/error。判断依据可用 HTTP 状态码先行分流。

认证白名单(无需 Token 即可访问的 /api 路径)
/api/auth/**                        // 注册、登录、Token 签发
/api/payment/**                     // 支付发起、确认、回调(第 09 章)
/api/membership/order               // 创建订单(第 09 章)
/api/membership/order/**            // 订单查询
/api/translation/platform-stats     // 平台公开统计
/static/**  /css/**  /js/**  /images/**  /webjars/**
/favicon.ico  /error

11.4 业务错误码总索引

汇总各章出现的错误码与典型触发场景,便于客户端统一建表处理:

error 错误码HTTP典型场景详见
VALIDATION_ERROR400@Valid 请求体校验失败(各 DTO 的 @Pattern / @Size / @NotBlank)11.2
BIND_ERROR400表单 / 查询参数绑定失败11.2
TYPE_MISMATCH400路径变量 / 参数类型转换失败11.2
ILLEGAL_ARGUMENT400业务参数非法:订单不存在、动态内容为空、方案 ordinal 越界等09 / 10 / 08
INVALID_ARGUMENT400动态发布 content 缺失(控制器内捕获)10.4
UNAUTHORIZED401控制器内 UserContext 为空(ApiResponse 结构的未登录响应)10.2-10.4
FILE_TOO_LARGE413上传文件超过大小限制(文档 50MB / 单请求 100MB)04 / 11.2
USER_NOT_FOUND404用户不存在(ResourceNotFoundException)10.2
ILLEGAL_STATE409状态冲突:订单非待支付 / 已过期、会员配额乐观锁重试超限、DashScope Key 未配置09 / 08 / 07
INSUFFICIENT_POINTS402点数与会员配额合计不足以完成翻译 / 会员配额不足 / 无有效会员08
MOMENTS_LIST_FAILED500动态列表查询内部异常10.4
MOMENTS_CREATE_FAILED500动态发布内部异常(含图片存储失败)10.4
NULL_POINTER / RUNTIME_ERROR / INTERNAL_ERROR500服务端内部错误(固定提示语,不泄露细节)11.2
推荐的客户端统一错误处理
async function apiFetch(url, options = {}) {
  const resp = await fetch(url, {
    ...options,
    headers: { 'Authorization': `Bearer ${token}`, ...options.headers }
  });

  // 拦截器 401:原生 JSON {code, message},需要重新登录
  if (resp.status === 401) { redirectToLogin(); return; }

  // SSE / 文件流等非 JSON 响应直接透传
  const ct = resp.headers.get('content-type') || '';
  if (!ct.includes('application/json')) return resp;

  const body = await resp.json();
  if (!body.success) {
    // body.error 为错误码,body.message 人读提示,body.data 常为具体原因
    throw new ApiError(body.error, body.message, body.data, resp.status);
  }
  return body.data;
}

11.5 附录 A:翻译引擎与支持语言

翻译引擎(translationEngine 合法值)
QWEN 通义千问大模型 ALIBABA_CLOUD 阿里云机器翻译

当前版本固定开放这两个引擎;传其他值或留空时由服务端按默认策略选择。 引擎不可用时自动降级为 Mock 占位结果并退还扣点(见 8.1)。

支持语言(SUPPORTED_LANGUAGES,共 10 种)
zh(中文)    en(英语)      ja(日语)    ko(韩语)    fr(法语)
de(德语)    es(西班牙语)  ru(俄语)    ar(阿拉伯语) pt(葡萄牙语)

所有语言相关字段(源 / 目标语言、术语语言对、用户默认语言配置)均使用上述小写代码; 源语言传 auto 时自动检测(检测语言不入库、不回写请求参数)。

11.6 附录 B:核心枚举速查

枚举取值出现位置 / 注意点
MembershipTypeEnumMONTHLY / QUARTERLY / YEARLY⚠️ 双重表示:/api/membership/plans 与 subscribe 用 ordinal(0/1/2);订单创建用枚举名字符串(见 8.3 / 9.3)
MembershipStatusEnumACTIVE(1) / EXPIRED(2) / CANCELLED(3)会员实体 status 字段
OrderStatusEnumPENDING(1) / PAID(2) / CANCELLED(3) / REFUNDED(4)订单状态机(见 9.5)
PaymentStatusEnumINITIATED / SUCCESS / FAILED支付记录状态
PaymentProviderEnumALIPAY / WECHAT / UNIONPAY / STRIPE / PAYPAL / OTHER支付渠道(当前可用渠道由 PaymentChannelRegistry 决定)
PaymentMethodEnumALIPAY_APP / ALIPAY_QR / WECHAT_APP / WECHAT_QR / UNIONPAY_QR / CREDIT_CARD / BANK_TRANSFER / OTHER支付方式
ProcessingStatusEnum7 个状态(文档任务生命周期)文档翻译任务(见第 04 章)
术语分类 categoryTECHNOLOGY / BUSINESS / MEDICAL / LEGAL / FINANCE / EDUCATION / SCIENCE / GENERAL正则限定的 8 个分类(见第 06 章)

11.7 附录 C:关键配置项速查

配置键默认值作用详见
server.port8090服务监听端口01
app.points.text-chars-per-point1000文本翻译每点对应字符数(≤0 时兜底 1 点/次)08
app.points.document-points-per-page1文档翻译每页扣点08
app.membership.monthly-quota5000会员单月配额基数(包季 ×3 / 包年 ×12)08
app.membership.subscribe-bonus-points5000开通会员一次性赠点08
ai.dashscope.api-key—通义千问引擎密钥;未配置时翻译走 Mock 降级、质量评估直接 40903 / 07
pay.alipay.enabledfalse支付宝真实渠道路由开关;关闭时 confirm 不发起线上查单09
SSE 相关30s 连接超时 / 20s 心跳对话翻译流式通道(chat-sse- 线程池 8 核心 / 20 最大 / 500 队列)05
上传限制单文件 50MB / 单请求 100MB超出即 413 FILE_TOO_LARGE04

🎉 至此全文完。建议从「第 01 章 快速开始」入手跑通第一个翻译请求, 再按业务域选读第 03-09 章;集成期遇到任何非 2xx 响应,可对照 11.4 的错误码索引快速定位。