← 返回文档首页

接口异常状态清单(App 端错误处理用)

2026-07-21 · 覆盖 54 个 Controller 全量接口 · 依据 seahub-core 源码逐个抽取
这份文档给 App 端做"按不同异常显示不同提示"用。先看第 1 节的全局错误码速查——那是 App 应该据此分支的一组稳定 code;再看第 2 节的处理建议;第 3 节按页面列出每个接口具体会返回哪些异常。务必先读第 0 节的两个"坑",否则很容易漏判错误。

0. 怎么读这份文档(两个必须先知道的坑)

所有接口的返回都是统一信封:{ "success": bool, "code": "XXX", "message": "...", "data": ... }。但判错有两个反直觉的地方:

坑一:不能只看 HTTP 状态码。有一部分"业务失败"是 HTTP 200 但 success=false(后端用 ApiResponse.fail 直接返回)。比如创作者等级查用户不存在(USER_NOT_FOUND)就是 200。App 判错的第一依据必须是 success 字段,不是 HTTP 状态码。
坑二:大部分业务错误的 code 都是 BAD_REQUEST,只有 message 不同。后端绝大多数业务校验是 IllegalArgumentException,统一映射成 400 / BAD_REQUEST,靠 message 文案区分(例如"invalid phone OTP""Coupon is expired""Withdraw amount is below minimum...")。所以:能靠稳定 code 分支的只有第 1 节那一小组;其余大量场景 App 只能直接把后端 message 展示给用户(这些 message 有的是中英双语、有的是纯英文,见第 4 节待改进点)。
HTTP 状态码的大致含义:400 参数/业务校验失败 · 401 未登录/登录失效/被顶号 · 429 触发限流 · 404 资源不存在(少数接口) · 422 状态不允许(少数接口) · 502 三方平台报错 · 500 服务器内部错误或三方超时/配置问题(见坑三)。
坑三(给"网络/重试"提示用):转链接、查商品详情这类同步调三方(Shopee/TikTok/Lazada)的接口,三方超时(默认 10 秒)和 Shopee 报错会塌缩成 500 INTERNAL_SERVER_ERROR,跟真正的服务器 bug 长得一样。所以在这几个特定接口(见 3.4 标 调三方 的)上收到 500,更可能是"网络/三方抖动",适合显示"网络不稳定,请重试"而不是"系统错误"。

1. 全局错误码速查(App 应该据此分支的稳定 code)

下面这些 code 是跨接口稳定、语义明确的,App 端应针对它们写专门的处理逻辑。其余 BAD_REQUEST 归为"直接展示 message"的兜底分支。

codeHTTP含义建议 App 处理
UNAUTHORIZED401未登录 / token 无效 / 登录已过期(refresh 也失效)清本地登录态,跳登录页。文案"登录已过期,请重新登录"
SESSION_REPLACED401账号已在其它设备登录,当前设备被顶下线(单设备登录)清登录态跳登录页,文案专门写"你的账号已在其他设备登录",与普通过期区分
RATE_LIMITED429请求过于频繁,触发网关限流提示"操作太频繁,请稍后再试",做退避重试,不要立刻重试
TOO_MANY_REQUESTS429发验证码等业务级频控(冷却/每小时上限)直接展示后端 message(已是中英双语),按钮进入倒计时冷却
PHONE_COUNTRY_NOT_SUPPORTED400手机号国家不支持(印尼只支持 +62)直接展示 message(印尼语文案),提示换号
EXTERNAL_PLATFORM_ERROR502三方平台(TikTok 等)明确报错"第三方暂时不可用,请稍后重试",可重试
ORDER_NOT_FOUND404订单不存在(仅订单收益详情接口)展示"订单不存在"空态
NOT_FOUND404路由/资源不存在一般是接口路径问题,兜底错误提示
INTERNAL_SERVER_ERROR500服务器内部错误三方超时/后端配置缺失(见坑三)普通接口:"系统繁忙请稍后重试";标 调三方 接口:优先"网络不稳定,请重试"
ADMIN_TOKEN_NOT_CONFIGURED503内部/运营接口(App 用不到)App 无需处理(仅运营端)
HTTP 200 + success:false 类: USER_NOT_FOUND(创作者等级查用户不存在)—— 注意这类失败是 HTTP 200,App 必须先判 success 字段再判 HTTP 状态。
邀请绑定类(400,可据 code 分支给友好文案): INVITE_CODE_NOT_FOUND 邀请码无效 · SELF_INVITE_NOT_ALLOWED 不能邀请自己 · USER_ALREADY_BOUND_TO_ANOTHER_INVITER 已被他人邀请 · INVITER_ROLE_NOT_ALLOWED 邀请人不合格 · INVITE_RELATION_CYCLE_NOT_ALLOWED 会形成循环 · INVITE_RELATION_BIND_FAILED 绑定失败兜底。
密码重置类(400,均有独立 code): OTP_DISABLED · UNSUPPORTED_COUNTRY_CODE · ACCOUNT_NOT_FOUND · PASSWORD_TOO_SHORT · OTP_EXPIRED_OR_NOT_FOUND · OTP_ATTEMPTS_EXCEEDED · INVALID_OTP_CODE · OTP_ALREADY_CONSUMED · MISSING_OTP_INTENT_ID · OTP_INTENT_HAS_NO_BOUND_USER

2. App 端处理建议(按异常类型归类做统一拦截)

建议在网络层做一个统一拦截器,先按下面顺序判定,再落到具体页面:

  1. 先判 success===false(不是先判 HTTP 状态),false 即失败,进入错误分支。
  2. 再看 code 命中第 1 节稳定码 → 走对应专门逻辑(顶号跳登录、限流冷却、三方重试等)。
  3. 否则(多为 BAD_REQUEST)→ 直接 toast 后端 message。这是覆盖面最大的兜底,所以后端 message 的可读性直接决定用户体验(见第 4 节,部分 message 目前是纯英文,已建议后端统一)。
  4. 401 系列一律清登录态跳登录,其中 SESSION_REPLACED 用差异化文案。
  5. 调三方 的接口上的 500 → 归到"网络/重试"文案,而不是"系统错误",并提供重试按钮。
  6. 搜索/推荐类接口不会报三方错(后端已把三方失败降级成 200 + warnings[])——App 拿到结果照常展示即可,可选择读 warnings 做灰度埋点,但不必给用户报错。

3.1 登录 / 注册页

接口状态codemessage / 触发
POST /api/v1/auth/phone/otp-intents
发送手机验证码
400BAD_REQUESTWhatsApp OTP is disabled / invalid Indonesian phone number / unsupported country code
400PHONE_COUNTRY_NOT_SUPPORTEDNomor ini tidak didukung. BeeX Indonesia hanya mendukung nomor Indonesia (+62).
429TOO_MANY_REQUESTS发送太频繁,请稍后再试(60s 冷却)/ 该号码验证码请求次数过多(5/时)/ 请求过于频繁(IP 100/时)
500INTERNAL_SERVER_ERRORWA/短信发送通道异常(三方)
POST /api/v1/auth/phone/otp-intents/{id}/verify
校验验证码登录
400BAD_REQUESTphone OTP expired or not found / invalid phone OTP / phone OTP attempts exceeded / phone OTP already consumed
401SESSION_REPLACED(极少)登录成功后旧会话被顶
POST /api/v1/auth/whatsapp/login-codes/consume
WhatsApp 登录码换 token
400BAD_REQUESTlogin code is required / invalid login code / login code not verified / login code conflict
GET /api/v1/auth/whatsapp/login-intents/{id}
轮询扫码登录状态
400BAD_REQUESTlogin intent not found
POST /api/v1/auth/password/login
手机号+密码登录
400BAD_REQUESTphone number not registered or account not found
400BAD_REQUESTlogin password not set, please use OTP login or set a password first
400BAD_REQUESTincorrect password
POST /api/v1/auth/apple/native · /google/id-token · /tiktok/callback
三方登录
400BAD_REQUEST(Apple)invalid/expired Apple identity token 等十余种;(Google)Invalid Google identity token / audience mismatch / email not verified;(TikTok)TikTok login failed / invalid TikTok login state / expired TikTok login state
502EXTERNAL_PLATFORM_ERROR(Google/TikTok)三方 token 校验接口调用失败
POST /api/v1/auth/refresh
刷新 token
401UNAUTHORIZED登录已过期(refresh token 失效/被吊销/过期,含被顶号后)
密码重置(/api/v1/auth/password-reset/*)有独立 code:OTP_DISABLED / UNSUPPORTED_COUNTRY_CODE / ACCOUNT_NOT_FOUND / PASSWORD_TOO_SHORT / OTP_EXPIRED_OR_NOT_FOUND / OTP_ATTEMPTS_EXCEEDED / INVALID_OTP_CODE / OTP_ALREADY_CONSUMED,均为 400,App 可据 code 给精准文案。

3.2 安全设置 / 密码 / 注销

接口状态codemessage / 触发
GET /api/v1/user/security/status 等全部安全接口400BAD_REQUESTuserId is required(未传 userId 且无 X-Beex-User-Id 头)
POST /api/v1/user/security/pay-password/otp-intents
发送设置支付密码验证码
400BAD_REQUESTuser not found: {userId}
422UNPROCESSABLE_ENTITYuser has no phone or WhatsApp number: {userId}
POST /api/v1/user/security/pay-password/otp-intents/{id}/verify-and-set
校验并设支付 PIN
400BAD_REQUESTpay password must be exactly 6 digits / OTP expired or not found / OTP attempts exceeded / invalid OTP code / OTP already consumed
POST /api/v1/user/security/login-password/verify · /pay-password/verify
校验密码是否正确
200OK密码错不是错误!返回 {valid:false},由 App 判断 valid 字段
POST /api/v1/account-deletion/intents
发起注销
400BAD_REQUESTuserId is required / user not found
422UNPROCESSABLE_ENTITYaccount deletion is disabled / user is not active / official whatsapp number is not configured

3.3 首页 / 商品浏览

好消息:商品搜索/推荐类接口对 App 几乎不报错。/products/high-commission/products/activity/products/by-shop/products/recommendations 内部调三方,但后端已把所有三方失败/超时降级成 HTTP 200 + warnings[],正常展示结果即可。唯一的错误是请求体里 countryCode/platform 枚举非法 → 400 BAD_REQUEST "Invalid request body"
接口状态codemessage / 触发
GET /api/v1/popular-brands · /campaigns/placements · /activity-campaigns/cards
首页各配置/榜单(纯查库)
400BAD_REQUESTNo enum constant ...CountryCode.XX(countryCode 非法,一般不会发生)
GET /api/v1/new-user-activity/status
新手任务
400BAD_REQUESTuserId 缺失 / countryCode 非法(用户不存在不报错,返回全 TODO)

3.4 转链接 / 分享 / 邀请

本组是"网络/重试"文案的主战场。/affiliate-links/generate/products/resolve 会同步调三方:TikTok 明确报错 → 502(可直接提示"第三方暂不可用");而 Shopee 报错、以及任意三方 10 秒超时 → 500,跟真 bug 无法区分。这两个接口上收到 500,请优先按"网络不稳定,请重试"处理并给重试按钮。
接口状态codemessage / 触发
POST /api/v1/affiliate-links/generate 调三方
生成推广/分享链接
400BAD_REQUESTUnsupported product platform: OTHER / Cannot extract TikTok product_id from productUrl...
502EXTERNAL_PLATFORM_ERRORTikTok Creator sharing link API error: code=... / TikTok Open API HTTP error: status=...
500INTERNAL_SERVER_ERRORShopee 报错、三方账号未授权/未配置、三方超时(message 被隐藏为 Internal server error)→ 按网络重试处理
POST /api/v1/products/resolve 调三方
解析链接查商品详情
400BAD_REQUESTUnsupported product platform / Cannot extract Shopee itemId / Cannot extract TikTok product_id / TikTok product {id} has no inventory
500INTERNAL_SERVER_ERRORShopee 未配置/未返回商品/报错/超时(TikTok、Lazada 会静默降级为兜底商品,不报错)→ 按网络重试处理
200OKTikTok/Lazada 失败时返回降级兜底商品,不报错
POST /api/v1/shopee/product-offers 调三方
Shopee 选品代理
400BAD_REQUESTShopee affiliate API is not configured
500INTERNAL_SERVER_ERRORShopee 报错 / 超时 → 按网络重试处理
POST /api/v1/links/parse
解析链接(纯本地正则)
400BAD_REQUESTurl 为空 / URL 非法(Illegal character in ...)
GET /api/v1/affiliate-shares/{shareCode} · /api/v1/growth/invite-shares
分享详情 / 生成邀请分享
400BAD_REQUESTShare link not found. / user not found / countryCode does not match current user / BeeX currently only supports inviting USER
POST /api/v1/rebate-fund/claim
领返利金(绑邀请)
400INVITE_CODE_NOT_FOUND 等见第 1 节"邀请绑定类"专门 code:邀请码无效/不能邀请自己/已被他人邀请/循环等

3.5 钱包 / 提现 / 支付

提现是全 App 错误最丰富的接口,几乎全是 400 BAD_REQUEST + 明确 message,App 直接展示 message 即可(建议后端把这些改成带 code,见第 4 节)。注意:"提现已关闭""管理员/回调 token 未配置"等被 IllegalStateException 吞成 500,拿不到真实原因。
接口状态codemessage / 触发
POST /api/v1/withdraw/apply
发起提现
400BAD_REQUESTPayment password is required before withdrawal / pay password must be exactly 6 digits / Invalid payment password
400BAD_REQUESTWithdraw amount is below minimum amount: N / exceeds per-transaction limit: N / exceeds daily amount limit: N / exceeds daily count limit: N
400BAD_REQUESTVerified payout profile is required before withdrawal / Withdraw fee must be less than amount
500INTERNAL_SERVER_ERROR提现被后台关闭(真实原因被吞)/ Xendit 非余额不足类失败 → 提示稍后重试
POST /api/v1/withdraw/payout-profile
保存收款账户
400BAD_REQUESTbankName/accountNumber 等必填校验 / countryCode 非法
GET /api/v1/withdraw/records/{id}
提现记录详情
400BAD_REQUESTWithdraw request not found(不存在或不属于本人,统一文案防枚举)
POST /api/v1/payments/create
创建支付/充值单
400BAD_REQUESTPayment amount must be greater than zero / must be a whole currency amount / bizType 非法
500INTERNAL_SERVER_ERROR支付渠道未配置(真实原因被吞)
GET /api/v1/payments/{id}
查支付单
400BAD_REQUESTPayment order not found
GET /api/v1/earnings/{userId}/summary · /commissions
收益/佣金
400BAD_REQUESTuser not found: {userId} / unsupported commission category: {x}
GET /api/v1/order-benefits/orders/{orderId}
订单收益详情
404ORDER_NOT_FOUNDorder not found(注意:这里是 404 + 专门 code,与提现的 400 not found 不同)
GET /api/v1/wallets/{userId}
钱包余额
无业务错误;钱包不存在返回 data:null + success:true

3.6 我的 / 收益 / 优惠券

接口状态codemessage / 触发
GET /api/v1/me/summary
我的页聚合
401 / 404UNAUTHORIZED / NOT_FOUNDauthentication required(未登录)/ user not found(用户不存在)
GET /api/v1/users/{userId}/profile · /me
个人资料
404 / 400NOT_FOUND / BAD_REQUESTuser not found / userId is required
PUT /api/v1/users/{userId}/profile
改昵称/头像
400BAD_REQUESTnickname must be 1-40 letters,numbers,spaces,or simple punctuation / avatarUrl is invalid
400BAD_REQUESTuser not found
POST /api/v1/users/{userId}/avatar 传 OSS
上传头像
400BAD_REQUESTavatar file is required / avatar file must be <= 2MB / avatar must be jpeg,png,webp,or gif
500INTERNAL_SERVER_ERROROSS 上传失败/未配置(真实原因被吞)→ 提示稍后重试
POST /api/v1/coupons/preview
优惠券试算
400BAD_REQUESTCoupon not found / Coupon is expired / Coupon is not available / Coupon minimum order amount not reached / This is a discount coupon and cannot be used for cashback. 等(纯英文,建议直接展示)
POST /api/v1/coupons/{id}/claim · /use · /cancel
领/用/取消券
200OK失败不报错!返回 {claimed:false}/{used:false},由 App 判断布尔字段
GET /api/v1/growth/users/{userId}/creator-tier
创作者等级
200USER_NOT_FOUND(200 + success:false)user not found: {userId}
POST /api/v1/growth/relations/bind
绑定邀请关系
400SELF_INVITE_NOT_ALLOWED 等见第 1 节"邀请绑定类"专门 code
GET /api/v1/growth/users/{userId}/children · /children-earnings · /relation
直邀用户 / 邀请关系
基本无业务错误

3.7 蜂蜜圈内容

接口状态codemessage / 触发
GET /api/v1/honey-feed/posts/{postId}
帖子详情
400BAD_REQUESTHoney feed post not found.(不存在或未发布)
POST /api/v1/honey-feed/posts/{postId}/shares
生成分享
400BAD_REQUESTHoney feed post not found. / shareUserId is required. / shareUserId does not match current user.
GET /api/v1/honey-feed/shares/{shareCode}
解析分享
400BAD_REQUESTHoney feed share not found. / Honey feed share is no longer available.
GET /api/v1/honey-feed/posts · /posts/snapshot
帖子列表(枚举参数)
500INTERNAL_SERVER_ERROR注意:此接口 countryCode 是枚举参数,传非法值会变成 500(不是 400)——App 务必传合法 countryCode

3.8 反馈 / 申诉 / 上传

接口状态codemessage / 触发
POST /api/v1/cashback-appeals
返现申诉
400BAD_REQUESTplatformOrderId is required / whatsappNumber is required / cashback appeal attachment url is invalid
注:本域没有"已提交过"去重,同一订单可重复提交
POST /api/v1/cashback-appeals/attachments · /api/v1/uploads/token · /api/v1/users/{id}/avatar 传 OSS
各类文件上传
400BAD_REQUESTfile is required / file must be <= 10MB(申诉)/ <=2MB(头像)/ must be jpeg,png,webp,or gif / unsupported upload bizType
500INTERNAL_SERVER_ERROROSS 未配置/签名失败/上传失败(真实原因被吞)→ 提示稍后重试
POST /api/v1/app-logs/feedback · GET /app-logs/upload-token
问题反馈/日志上传
400BAD_REQUESTcountryCode/description 必填 / urls 不能为空 / App log OSS upload is not configured

3.9 推送 / App 配置 / 其它

接口状态codemessage / 触发
POST /api/v1/push/devices/register
注册推送 token
400BAD_REQUESTmust not be blank(countryCode/userId/deviceId/platform/pushToken)/ 枚举非法
GET /api/v1/app/runtime-config · /api/v1/countries
启动配置/国家列表
无业务错误(参数容错,均有默认)
GET /api/v1/app/h5-package/latest
H5 包更新检查
400BAD_REQUESTcountryCode 非法(无可用包是正常 noUpdate 响应,不报错)
GET/POST /api/v1/integrations/tiktok/* 调三方
TikTok 授权/选品(运营向)
502EXTERNAL_PLATFORM_ERRORTikTok Open API HTTP error / TikTok API error(三方失败);参数缺失为 400

4. 后端已知待改进点(建议排期,不阻塞 App 接入)

下面几条是这次全量梳理时发现的、会直接影响 App 体验的一致性问题,建议后端后续统一,能让 App 端判错更简单:

  1. 大量业务错误共用 BAD_REQUEST,只能靠 message 区分。提现、优惠券、登录等关键路径建议逐步补上专门 code(像密码重置那样),App 就能据 code 做多语言文案,而不是直接展示后端英文 message。
  2. 一批错误 message 是纯英文(优惠券、提现、个人资料校验等),App 直接展示会露出英文。建议后端要么补 code 让 App 自己多语言,要么把面向用户的 message 统一成印尼语/双语。
  3. 三方超时、Shopee 报错、OSS/配置失败被 IllegalStateException/超时异常吞成 500,真实原因只进日志不返回。建议后端把"三方不可用/超时"单独映射成一个可识别的 code(如 UPSTREAM_TIMEOUT/UPSTREAM_UNAVAILABLE),App 就能精准显示"网络/重试"而不是猜。
  4. 两种"不存在"写法不一致:提现/支付用 400 "... not found",订单收益用 404 ORDER_NOT_FOUND。建议统一。
  5. 枚举型 @RequestParam(如蜂蜜圈列表的 countryCode)传非法值会变 500 而非 400,与其它接口不一致。建议统一成 400。
  6. 部分"业务失败"用 HTTP 200 + success:false(如创作者等级 USER_NOT_FOUND),与其它 4xx 风格不一致——这条 App 侧只要坚持"先判 success 再判 HTTP"就不受影响,但值得后端知晓。