fix(realname): 业务 code 优先于 HTTP 状态码,并区分额度耗尽

实测服务商业务失败时 HTTP 状态码会跟着变(身份证号错误返回 400
且 result 为 null),按状态码判断会把第三方异常误判成入参错误。
改为以业务 code 为准,仅在拿不到 code 时退回状态码与网关错误头。

额度耗尽(x-ca-error-code=B403MQ)此前与限流同样提示「请求过于频繁,
请稍后再试」,但重试不会恢复,新增 ErrProviderQuotaExhausted 并提示
联系客服。网关错误原因只在响应头,一并带进错误信息便于排查。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
yml2213
2026-10-02 12:03:52 +08:00
co-authored by Cursor
parent 0b220829bb
commit 281bb4be59
5 changed files with 123 additions and 28 deletions
+23 -3
View File
@@ -74,7 +74,18 @@ Body 无参数。
}
```
注意 `code` 是业务返回码,并非 HTTP 状态码。
注意 `code` 是业务返回码,并非 HTTP 状态码。实测业务失败时 HTTP 状态码会跟着变(例如身份证号错误时
返回 `400` 且 `"result": null`),因此解析必须以 `code` 为准,不能按 HTTP 状态码判断失败类型。
网关层错误(AppCode 无效、限流、额度耗尽)不会返回上面的 JSON,响应体为空,原因只在响应头:
```text
x-ca-error-code: A401AC
x-ca-error-message: Invalid AppCode `not exists`
```
常见网关错误码:`A401AC`(AppCode 无效,HTTP 401)、`B403MQ`(套餐额度耗尽,HTTP 403)、
`B403FQ`(调用频率过高,HTTP 403)。额度耗尽与限流都是 403,但额度耗尽靠重试不会恢复,必须续购。
## 错误码
@@ -109,8 +120,17 @@ REALNAME_CLOUDMARKET_APPCODE=<阿里云市场 AppCode>
| `code` 为 400 / 20010 / 20310 | `ErrInvalidRealnameInput`,接口返回 400 |
| `code` 为 404 / 604 | `ErrProviderConfigInvalid`,接口返回 503 |
| `code` 为 500 / 501 / 1001 等其他值 | `ErrProviderUnavailable`,接口返回 502 |
| HTTP 403 / 429(网关限流) | `ErrProviderRateLimited`,接口返回 429 |
| HTTP 401 / 404(AppCode 或路径错误) | `ErrProviderConfigInvalid`,接口返回 503 |
| 403 且 `x-ca-error-code=B403MQ`(额度耗尽) | `ErrProviderQuotaExhausted`,接口返回 503「额度已用尽」 |
| 其他 403 / 429(网关限流) | `ErrProviderRateLimited`,接口返回 429 |
| HTTP 401 / 404 且无业务 code(AppCode 或路径错误) | `ErrProviderConfigInvalid`,接口返回 503 |
业务 `code` 的优先级高于 HTTP 状态码,只有响应体里拿不到 `code` 时才按状态码与网关错误头判断。
## 更换 AppCode
AppCode 与阿里云市场的订购关系绑定,**换商品必须换 AppCode**:旧商品的 AppCode 调用本接口会得到
`401 Invalid AppCode 'not exists'`。在「阿里云市场 → 已购买的服务 → 对应商品」获取 AppCode 后,
只需更新服务器 `backend/.env` 的 `REALNAME_CLOUDMARKET_APPCODE` 并重启后端,无需重新发版。
该接口不返回服务商流水号,因此 `user_realname.provider_order_no` 对 cloudmarket 渠道为空。
姓名与身份证号由本项目自行脱敏入库,并用 `pkg/crypto` 加密保存完整值。