API 网关要保留上游状态码:让权限、限流和故障能被客户端识别
本文目录
网关把响应体转发出去却统一返回 200,会破坏浏览器、SDK、监控和缓存共同依赖的 HTTP 语义。JSON 里的 code 字段可以表达业务错误,但不能把 401、403、429 和 5xx 的传输结果抹掉。
状态码应当回答什么
- 400:请求语法或字段不合法;客户端修正后再发。
- 401:当前请求缺少有效身份认证;会话过期时提示重新登录。
- 403:身份可识别但不允许该操作;通常不要用同一凭证盲目重试。
- 404:资源不存在,或服务端选择不暴露该资源存在性。
- 409:状态冲突,例如重复提交或版本冲突;应返回可理解的冲突原因。
- 413:请求体超过边界;前后端与反向代理的限制需要一致。
- 429:请求过快;如有 Retry-After,客户端按其延迟并加入抖动。
- 502/503/504:上游响应无效、服务暂不可用或网关等待超时。
响应体应提供稳定错误码、用户可理解消息和 requestId;不要把内部堆栈、主机名、token 或原始异常回显给客户端。每种状态的选择要和调用方契约一致。
代理边界
JSON API 可转发上游状态、经过白名单过滤的响应头及响应体。不要把 Set-Cookie、hop-by-hop 头、内部追踪数据和任意 Location 无条件暴露;Authorization、Cookie 和 IP 转发也要有明确的信任来源。网关自己生成的错误应使用准确的 502/503/504,而不是把本地连接错误包装为成功。
上传、下载和 SSE 不能经过会把流读入 JSON body 的通用代理。文件按流转发并施加体积、超时与中止限制;SSE 关闭代理缓冲并维持长连接;WebSocket 要显式配置 Upgrade 语义。客户端断开时应取消上游请求,避免已经无人等待的工作继续消耗资源。
超时、重试和幂等
为 DNS/连接、首字节和总业务预算分别设上限,并用 AbortSignal 传播取消。只对明确幂等的读取或带稳定幂等键的写请求做有限重试;不要在网关上自动重放非幂等上传、扣费或创建请求。重试需要次数上限、指数退避和抖动,且要记录实际重试次数,避免服务间重试叠加成放大器。
Node 代理伪代码
async function forwardJson(req, res, upstream, fetchImpl) {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 8000);
req.on('aborted', () => controller.abort());
try {
const response = await fetchImpl(upstream, {
method: req.method,
headers: selectAllowedHeaders(req.headers),
body: req.method === 'GET' || req.method === 'HEAD' ? undefined : req,
signal: controller.signal,
duplex: req.method === 'GET' || req.method === 'HEAD' ? undefined : 'half',
});
res.status(response.status);
copyResponseHeadersFromAllowlist(response.headers, res);
response.body.pipeTo(Writable.toWeb(res));
} catch (error) {
if (!res.headersSent) res.status(502).json({ code: 'UPSTREAM_FAILURE' });
} finally {
clearTimeout(timer);
}
}
这是展示状态传递和取消位置的伪代码,不可直接替代框架适配器:真实项目必须处理 request stream 生命周期、响应流错误、错误发生时 header 是否已发送、内容长度/编码和框架 API。对流式请求尤其要做集成测试。
监控与测试
指标按上游服务、状态码类别和路由模板聚合,不用用户 id、完整 URL 参数等高基数字段作为标签。分别验证成功、未登录、权限拒绝、资源不存在、429 带 Retry-After、上游断开、超时、客户端提前关闭、慢速上传和 SSE 首包延迟。部署前后对比错误率、P95/P99、上游耗时和连接数。
参考:RFC 9110 HTTP Semantics、Node.js AbortSignal、Nginx proxy buffering。
Live Notes
留言提交后会先进入审核,审核通过后对其他读者公开。