Skip to content
sungaowei edited this page Oct 16, 2026 · 2 revisions

错误处理 (Errors)

English Version | 简体中文


SDK 返回的所有错误均实现了 typesafe.TypeSafeError 接口。 所有非 2xx 的 HTTP 失败状态码都会映射为具体的强类型错误结构体,并且每个类型化错误均嵌套了 *APIError(并支持 Unwrap() 解包),因此你可以使用标准库 errors.As 既匹配特定子类型,也匹配通用的 *APIError。


HTTP 状态码映射

状态码 错误类型 说明
400 *BadRequestError 请求参数有误或 JSON 格式非法
401 *AuthenticationError API Key 缺失、无效或已过期
403 *PermissionDeniedError 账号权限不足,例如未开通相关模型
404 *NotFoundError 请求的端点或资源不存在
413 *PayloadTooLargeError 请求体超过 32 MiB 限制,或单张图片超过 16 MiB 上限
415 *UnsupportedMediaTypeError 请求的 Content-Type 不受支持,或图片格式非法(仅支持 PNG/JPEG)
422 *UnprocessableEntityError 业务语义校验失败(如字段值不合法)
429 *RateLimitError 触发接口限流,附带 RetryAfter() (time.Duration, bool)
529 *OverloadedError 服务端处于过载保护中,附带 RetryAfter()
5xx *InternalServerError 服务端内部异常
其他非 2xx *APIError 其他未显式列出的非正常 HTTP 响应

客户端非 HTTP 错误

错误类型 触发原因
*SDKError 本地配置非法、非法输入参数、无法序列化的请求体,绝不是网络对端返回的状态码。
*APIConnectionError 网络握手失败、DNS 解析失败或 TCP 提前断开,从未收到 HTTP 响应。
*APITimeoutError 请求超出配置的超时上限,包含 Timeout time.Duration。
*APIResponseValidationError 服务端返回了 2xx 成功状态码,但响应体格式不符合预期,包含出错字段路径 FieldPath。
*ScoreError 构建 Score 问题时评分阶梯少于 2 级或为空。

APIError 上下文信息

所有 HTTP 错误底层嵌套的 *APIError 均携带了详尽的网络上下文:

type APIError struct {
	Status    int         // HTTP 响应状态码(如 400, 429, 500 等)
	Body      any         // 解析后的 JSON 错误对象、纯文本内容或 nil
	RawBody   []byte      // 服务端返回的原始未经修改的二进制字节
	Headers   http.Header // 完整的响应标头
	Endpoint  string      // 脱敏后的 "METHOD URL"(剔除了密码、Query 和 Hash)
	RequestID string      // 服务端响应标头 x-typesafe-request-id,便于工单排查
	Message   string      // 从响应体中智能提取的人类可读错误详情
}

其 Error() 方法格式化为:<METHOD URL>: <status> <message> (request_id=<id>),会自动省略不适用的空字段。


错误捕获处理范例

response, err := client.SystemOne(ctx, state, questions)
if err != nil {
	var rateLimit *typesafe.RateLimitError
	var payloadTooLarge *typesafe.PayloadTooLargeError
	var validation *typesafe.APIResponseValidationError
	var timeout *typesafe.APITimeoutError
	var apiErr *typesafe.APIError

	switch {
	case errors.As(err, &rateLimit):
		if wait, ok := rateLimit.RetryAfter(); ok {
			log.Printf("触发限频,建议等待 %v 后重试", wait)
		}
	case errors.As(err, &payloadTooLarge):
		log.Printf("请求体过大 (超过 32 MiB 或图片超过 16 MiB): %v", payloadTooLarge)
	case errors.As(err, &validation):
		log.Printf("响应数据字段校验失败: %q", validation.FieldPath)
	case errors.As(err, &timeout):
		log.Printf("请求超时 (单次上限: %v)", timeout.Timeout)
	case errors.As(err, &apiErr):
		log.Printf("HTTP %d (请求 ID: %s): %s", apiErr.Status, apiErr.RequestID, apiErr.Message)
	default:
		log.Printf("调用失败: %v", err)
	}
	return err
}

匹配原则:优先匹配最具体的类型(如 *RateLimitError、*PayloadTooLargeError),最后再回退到 *APIError。


快速提取辅助函数

SDK 提供了一组开箱即用的类型提取函数,均遵循 Go 惯用的 (value, bool) 签名:

辅助函数 匹配目标
typesafe.AsAPIError(err) 任意非 2xx HTTP 失败
typesafe.AsRateLimitError(err) HTTP 429,或兼容的 HTTP 529
typesafe.AsOverloadedError(err) HTTP 529 服务端过载
typesafe.AsPayloadTooLargeError(err) HTTP 413 负载过大
typesafe.AsUnsupportedMediaTypeError(err) HTTP 415 不支持的媒体类型
typesafe.AsTimeoutError(err) 请求超时
typesafe.AsValidationError(err) 成功状态码但解析失败的响应
if ptlErr, ok := typesafe.AsPayloadTooLargeError(err); ok {
	log.Printf("413 错误: %s", ptlErr.Message)
}

智能消息提取机制

SDK 会自动根据主流 API 规范与反向代理格式,从响应体中提取最核心的 Message 说明文本:

响应体格式 提取出的 Message
{"error": "..."} 对应字符串
{"error": {"message": "..."}} 嵌套字典中的 message
{"message": "..."} 对应字符串
{"detail": "..."} 对应字符串
{"detail": {"message": "..."}} 嵌套字典中的 message
{"detail": [{"loc": [...], "msg": "..."}]} 多段错误拼接为 path: msg; ...,并剔除前导 body.
单独的 JSON 裸字符串 对应字符串
其他非结构化内容 截取前 200 个字节并附加 … 省略号

Clone this wiki locally