后端面试:代理改写响应时,如何正确使用 HTTP 203?
题干与适用场景
你负责一个 API 网关,代理可能过滤恶意附件、移除隐私字段或转码响应。源站请求成功,但下游收到的表示已经不是源站原样。请说明何时返回 203、如何更新缓存验证器、怎样避免客户端把代理内容误当成权威源站数据。
HTTP 203 是成功响应,表示转换代理修改了源站 200 响应的头字段或内容。它适合需要把“已成功但经过中间层改写”显式传给客户端的场景,不应被当作通用错误码或权限拒绝码。
面试官考察点
- 能否准确区分 203、200、304、4xx 和 5xx 的语义。
- 能否说明转换代理为何影响缓存、ETag、签名和后续请求。
- 能否设计原始表示与转换表示的审计关联。
- 能否处理多层代理重复转换、回源失败和客户端不理解 203。
- 能否把协议语义落到可测试的响应头与缓存行为。
回答前需要澄清的问题
- 改写是安全过滤、压缩转码还是个性化字段移除?它决定是否仍可共享缓存。
- 客户端能否识别 203?若不能,网关是否要保守返回 200 并在自有元数据中说明转换?
- 原始内容是否需要可追溯?签名、ETag 和审计记录必须绑定原始与转换版本。
- 转换是否确定性?相同源站版本若因规则不同产生不同表示,缓存键必须包含规则版本。
30 秒回答框架
我先确认网关是否真的改变了成功响应的内容或头字段。若源站成功且代理改写了表示,可用 203 明确告知客户端;未改写则保留 200。203 不代替 304,304 只表示客户端缓存仍可使用。转换后重新计算适用于下游表示的 ETag,避免复用源站校验器;缓存键加入内容协商、规则版本和租户边界。审计记录同时保存源站版本、转换规则和输出摘要,回源失败仍按实际失败语义返回。
分步骤深入解答
1. 先建立状态码边界
200 表示当前响应成功,未声明中间层改变了表示;203 表示请求成功但转换代理修改了源站 200 的头字段或内容;304 不携带新表示,只告诉客户端复用已验证缓存。过滤失败、权限拒绝和回源超时分别使用对应的 4xx 或 5xx 语义。
2. 识别转换类型
恶意附件替换链接、隐私过滤、格式转码和镜像标记都可能形成 203。只改变传输层压缩或 hop-by-hop 头通常不应宣称应用表示被改写。网关要在内部记录“源站表示”和“下游表示”的差异。
3. 重新处理验证器
源站的 ETag 描述源站表示,转换后的实体应生成新的、只对下游表示有效的 ETag。若转换是按规则版本决定的,规则版本必须进入缓存键或 ETag 计算输入;否则规则升级后客户端可能错误复用旧结果。
4. 设计缓存和协商
Vary、内容编码、语言、租户和过滤规则都会影响可共享性。对含用户隐私的转换结果默认私有缓存;对公共、确定性转换可共享,但要限制缓存范围。收到下游 If-None-Match 时,网关应针对自己的转换表示验证,不能直接把源站 304 透传给已改变的下游表示。
5. 保护签名与审计
若源站签名覆盖原始字节,改写后该签名不能继续证明下游内容。网关应明确签名主体,必要时重新签名或删除不再有效的签名头。审计事件记录源站请求 ID、源 ETag、规则版本、输出 ETag、转换原因和操作者。
6. 处理多层代理
多个代理可能连续转换。每层都要避免覆盖前一层的审计关联,并在转换不具幂等性时停止重复处理。若下游不理解 203,协议适配层可以返回 200,但必须通过文档化扩展头或专用元数据暴露转换状态,不能悄悄丢失安全信号。
7. 验证与回滚
测试源站 200、代理改写后 203、未改写 200、客户端缓存命中 304、规则升级、回源超时和过滤器失败。回滚规则时验证新旧 ETag 不冲突,并检查缓存中是否仍存在由旧规则生成的共享对象。
高质量示范回答
我会把 203 当作“成功,但转换代理改变了源站表示”的协议声明。源站成功且没有应用层改写时返回 200;改写了内容或相关头字段时返回 203;304 只用于验证下游已有表示,不能因为源站返回 304 就忽略转换层。网关为转换后的表示重新生成 ETag,并把规则版本、内容协商和隐私边界纳入缓存键。源站签名若覆盖原始字节,改写后必须重新签名或移除。每次转换记录源 ETag、规则版本和输出摘要,测试 200/203/304、规则升级、多层代理和回源失败,确保客户端不会把过滤后的内容当成源站原文。
常见错误
- 所有代理响应都返回 203 → 语义失真且影响客户端处理 → 只有成功且表示确实被改写时使用。
- 继续复用源站 ETag → 下游验证器对应错误表示 → 为转换结果重新计算 ETag。
- 把 203 当错误码 → 客户端可能重试或告警 → 失败使用真实的 4xx/5xx 语义。
- 透传源站 304 → 转换层可能跳过必要的重新验证 → 针对下游表示验证缓存。
- 忽略规则版本 → 规则升级后命中旧缓存 → 规则版本加入缓存键或验证器。
追问及应对
代理只改了 Content-Encoding,是否需要 203?
通常不需要。传输编码属于传输层处理;若没有改变应用层表示,保留 200,并按 HTTP 缓存规范处理编码协商。
203 响应可以被共享缓存吗?
可以,但前提是转换确定、缓存键包含所有变化维度,并且内容没有用户隐私。租户或用户相关过滤应使用私有缓存。
源站返回 203,网关又改写一次怎么办?
保留两层转换的关联,重新计算最终表示的 ETag,并确保规则具备幂等性;无法保证时只允许一次转换或拒绝重复处理。
客户端只接受 200,是否把 203 改成 200?
可以在明确的兼容层做,但要附带可识别的扩展元数据并记录降级。不能静默隐藏安全过滤或隐私改写。
回源返回 304,但本地没有转换后的缓存对象怎么办?
不能直接返回 304。网关需要取回可用表示、重新执行转换,或返回能反映缺少本地表示的失败结果。