错误格式
所有错误响应遵循一致的结构:
{
"data": null,
"errors": [
{
"message": "Missing required field: name",
"layer": "product"
}
]
}
读取错误数组
errors 数组按从根本原因到顶层调用者的顺序排列:
errors[0] — 根本原因(最有用的调试信息)
errors[n] — 暴露错误的顶层调用者
大多数情况下,您只需检查 errors[0].message 即可获得可操作的错误描述。
HTTP 状态码
| 状态码 | 含义 | 说明 |
|---|
| 200 | 成功 | 请求处理成功 |
| 400 | 错误请求 | 参数无效或请求体格式错误 |
| 401 | 未授权 | 缺少或无效的认证凭据 |
| 403 | 禁止访问 | 凭据有效但权限不足 |
| 404 | 未找到 | 请求的资源不存在 |
| 409 | 冲突 | 幂等请求正在处理中 |
| 429 | 请求频率限制 | 短时间内请求过多 |
| 500 | 服务器错误 | 内部服务器错误 |
| 501 | 未实现 | 请求的功能尚未开放 |
| 502 | 网关错误 | 上游服务错误 |
错误层级
每个错误包含一个 layer 字段,指示错误在系统中的来源:
| 层级 | 说明 | 常见原因 |
|---|
gateway | 请求路由 | 无效 URL,服务不可用 |
user | 认证 / 授权 | 令牌过期,角色错误 |
store | 商店操作 | 商店不存在,权限不足 |
product | 产品操作 | 价格无效,缺少字段 |
order | 订单操作 | 产品版本无效,结账错误 |
graphql | GraphQL 查询 | 查询无效,未知字段 |
常见错误场景
认证错误 (401)
{
"data": null,
"errors": [
{
"message": "Token has expired",
"layer": "user"
}
]
}
解决方案:
- 验证 Merchant ID 和私钥是否正确
- 确保 SDK 已使用有效凭据初始化
- 确保私钥与注册的公钥匹配
验证错误 (400)
{
"data": null,
"errors": [
{
"message": "Store name must be between 1 and 100 characters",
"layer": "store"
}
]
}
解决方案:
- 检查必填字段是否存在
- 验证字段值的格式和约束
- 确保金额使用最小货币单位(整数)
权限错误 (403)
{
"data": null,
"errors": [
{
"message": "Only store owner can delete store",
"layer": "store"
}
]
}
解决方案:
- 验证 API Key 是否具有所需权限
- 确保用户属于正确的商店
幂等性冲突 (409)
{
"data": null,
"errors": [
{
"message": "Request with this idempotency key is already being processed",
"layer": "gateway"
}
]
}
解决方案:
- 等待原始请求完成
- 使用不同的
X-Idempotency-Key 发起新请求
代码中处理错误
TypeScript SDK
import { WaffoPancake, WaffoPancakeError } from "@waffo/pancake-ts";
const client = new WaffoPancake({
merchantId: process.env.WAFFO_MERCHANT_ID!,
privateKey: process.env.WAFFO_PRIVATE_KEY!,
});
try {
const { store } = await client.stores.create({ name: "My Store" });
} catch (err) {
if (err instanceof WaffoPancakeError) {
const rootCause = err.errors[0];
console.error(`Error [${rootCause.layer}]: ${rootCause.message}`);
// err.status 包含 HTTP 状态码
}
}
---
## 重试策略
对以下状态码使用指数退避重试:
- **429** -- 请求频率限制(如有 `Retry-After` 头,请遵守)
- **500** -- 内部服务器错误
- **502** -- 网关错误
```javascript
async function retryRequest(fn, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
const status = error.status;
if (![429, 500, 502].includes(status) || attempt === maxRetries - 1) {
throw error;
}
const delay = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
不要重试 400、401、403 或 404 错误。这些错误表明请求本身需要修复。
幂等性安全重试
使用 X-Idempotency-Key 请求头安全重试写操作,避免创建重复记录:
curl -X POST https://waffo-pancake-auth-service.vercel.app/v1/actions/checkout/create-session \
-H "Content-Type: application/json" \
-H "X-Store-Slug: your-store-slug" \
-H "X-Environment: test" \
-H "X-Idempotency-Key: order-abc-123" \
-d '{"productId": "...", "productType": "onetime", "currency": "USD"}'
- 幂等键缓存 24 小时
- 发送相同的键返回缓存的响应
- 如果原始请求仍在处理中,返回
409 Conflict