按状态分类
先按 HTTP/gRPC 状态决定登录、权限、重试或刷新本地状态。
HTTP API 使用 Google RPC Status 风格的统一 JSON 错误体:
{ "code": 16, "message": "Invalid username or password", "details": [ { "@type": "type.googleapis.com/google.rpc.ErrorInfo", "reason": "UNAUTHENTICATED", "domain": "synctv.api", "metadata": { "errorCode": "1002", "errorKind": "unauthenticated", "requestId": "01HX..." } }, { "@type": "type.googleapis.com/google.rpc.RequestInfo", "requestId": "01HX..." } ]}字段含义:
| 字段 | 说明 |
|---|---|
code | gRPC 状态码数字。HTTP 状态仍来自 HTTP status line。 |
message | 可展示的错误摘要。5xx 会被服务端脱敏。 |
details[] | 结构化错误详情,通常包含 google.rpc.ErrorInfo,带 reason、domain 和 metadata。 |
details[].metadata.errorCode | 应用错误码,用于程序化处理。 |
details[].metadata.requestId / google.rpc.RequestInfo.requestId | 请求 ID。排查服务端日志时优先提供它。 |
429 可能带 Retry-After header,客户端应按它退避。
| 状态 | 含义 | 客户端动作 |
|---|---|---|
400 | 请求结构、字段或格式错误 | 修正输入,不要用相同请求重试 |
401 | 未登录、token 失效、ticket 失效、Provider 凭据失效 | 刷新 token、重新登录或重新绑定 Provider |
403 | 身份有效但无权限、邮箱未验证、被封禁 | 展示权限原因,不要无限重试 |
404 | 资源、房间、媒体、Provider instance 不存在 | 刷新本地列表或引导返回 |
409 | 已存在、并发修改、状态冲突 | 重新拉取资源后再提交 |
408 | 后端请求超时 | 可退避重试,保留 requestId |
429 | 限流或资源耗尽 | 使用 Retry-After 或指数退避 |
502 | 上游 Provider 或代理错误 | 检查 Provider、上游状态和 header |
503 | 数据库、Redis、邮件、Provider 或服务依赖不可用 | 稍后重试,运维查看依赖健康 |
504 | 上游超时 | 退避重试,检查上游和网络 |
错误码按区间分组:
| 区间 | 代码 | 含义 |
|---|---|---|
| 通用 | 0 | 未指定错误 |
| 认证 | 1000 | 未认证 |
| 认证 | 1001 | token 过期 |
| 认证 | 1002 | 凭据错误 |
| 资源 | 2000 | 资源不存在 |
| 资源 | 2001 | 资源已存在 |
| 资源 | 2002 | 资源耗尽或限流 |
| 资源 | 2003 | 状态冲突 |
| 校验 | 3000 | 参数无效 |
| 校验 | 3001 | 格式无效 |
| 校验 | 3002 | 值太短 |
| 校验 | 3003 | 值太长 |
| 校验 | 3004 | 缺少必填字段 |
| 权限 | 4000 | 权限不足 |
| 权限 | 4001 | 禁止访问 |
| 权限 | 4002 | 被封禁 |
| 服务端 | 9000 | 内部错误 |
| 服务端 | 9001 | 数据库错误 |
| 服务端 | 9002 | 服务不可用 |
| 服务端 | 9003 | 超时 |
客户端不应依赖 message 文本做稳定分支;文本可能为了可读性或安全脱敏而变化。
gRPC 使用标准 status code、message 和嵌入的 google.rpc.Status binary details。HTTP 的 x-synctv-error-code 元数据不会作为独立 trailer 发送;客户端应读取 google.rpc.ErrorInfo.metadata.errorCode 和 RetryInfo。常见映射:
| gRPC code | HTTP 类比 | 含义 |
|---|---|---|
InvalidArgument | 400 | 参数或格式错误 |
Unauthenticated | 401 | 缺少或无效认证 |
PermissionDenied | 403 | 身份有效但无权限 |
NotFound | 404 | 资源不存在 |
AlreadyExists | 409 | 资源已存在 |
ResourceExhausted | 429 | 限流或容量耗尽 |
Unavailable | 503 | 依赖或服务不可用 |
DeadlineExceeded | 504 | 超时 |
Internal | 500 | 服务端内部错误 |
调试方式见 gRPC 调试。
WebSocket 业务错误通过 protobuf 消息返回,不是 HTTP JSON:
| 消息 | 场景 |
|---|---|
ServerMessage.error | 普通业务错误,例如权限不足、输入无效 |
ServerMessage.resourceObserveError | 资源观察失败,例如 observe id 无效、超过订阅上限、资源加载失败 |
| WebSocket close | 认证失败、ticket 失效、协议错误、连接限制或服务关闭 |
资源观察错误不会自动关闭连接。客户端应修正订阅、减少观察数量或退避重试。
Provider 错误需要区分 SyncTV 与上游:
| 现象 | 典型状态 | 处理 |
|---|---|---|
| Provider 凭据失效 | 401 | 重新登录或重新绑定 Provider |
| 上游资源不存在 | 404 | 刷新列表,移除失效媒体 |
| 上游拒绝请求 | 400 或 502 | 检查 header、URL、格式 |
| 上游限流或 5xx | 502/503/504 | 退避重试,观察上游状态 |
| 未配置凭据加密 | 500 脱敏错误 | 管理员配置 credential encryption key |
按状态分类
先按 HTTP/gRPC 状态决定登录、权限、重试或刷新本地状态。
使用错误码
从 google.rpc.ErrorInfo.metadata.errorCode 读取应用错误码,不解析英文错误文本。
记录 requestId
用户提交问题时收集 requestId、时间、路径和状态码。
保护敏感信息
不要记录 token、Cookie、OAuth2 code、Provider 凭据或密码。