代表性面试主题

后端面试:如何用 HTTP Prefer 协商响应,而不破坏幂等与缓存?

后端中等
Offer.cc 编辑团队发布 更新

题干

一个批量 API 允许客户端选择返回最小响应或完整表示,并可请求服务端等待短时间完成。你会如何使用 Prefer、Preference-Applied 和缓存策略,确保偏好未被满足时客户端仍能安全处理?

题干与适用场景

批量写入 API 的客户端有不同带宽和延迟目标:有的只需要状态,有的需要完整资源表示,还有的愿意等待几秒以避免轮询。请基于 RFC 7240 设计 Prefer 请求头、Preference-Applied 响应头、错误处理、缓存和降级。

Prefer 是请求偏好,不是服务器必须满足的指令。题目考察协议语义与 API 契约设计,不代表所有代理都会完整保留偏好头。

面试官考察点

  • 能否区分客户端偏好与服务器承诺,并在响应中明确实际采用的偏好。
  • 能否正确使用 return=minimalreturn=representationrespond-asyncwait
  • 能否处理 Prefer 导致的响应差异、Vary、缓存键和代理兼容。
  • 能否让重试、幂等键和异步任务状态在偏好未满足时仍然安全。

回答前需要澄清的问题

  1. API 是安全读取还是有副作用的写入,是否已有幂等键?
  2. 完整表示的大小、生成成本和最大等待时间是多少?
  3. 客户端能否接受 202 与状态资源,是否支持轮询或回调?
  4. 中间代理是否会透传 Prefer,缓存是否可能共享?
  5. 偏好未满足时,客户端需要看到哪些稳定字段?

30 秒回答框架

“Prefer 表达客户端偏好,服务器可以忽略或只部分采用;采用后用 Preference-Applied 明确回显。写入请求可用 return=minimal 减少响应,调试或同步场景可用 return=representation,长任务可用 respond-async 和有上限的 wait。我会把幂等键、202 状态资源、缓存 Vary 和客户端降级一起设计:没有 Preference-Applied 就按默认响应解析,不能假设偏好一定生效。”

分步骤深入解答

1. 把偏好当作可忽略协商

RFC 7240 定义 Prefer 请求头及 Preference-Applied 响应头。服务端可选择不应用偏好;因此响应体和状态码必须有稳定的默认契约,客户端不能仅凭发送了 Prefer 就跳过解析。

2. 选择合适的偏好令牌

return=minimal 适合只需要成功确认的写入;return=representation 适合希望拿到更新后资源的同步调用。respond-async 表示客户端接受异步处理,wait=n 表示愿意等待的时间上限。把这些令牌当作预算提示,不要把 wait 当作 SLA 保证。

3. 设计响应确认

采用偏好时返回 Preference-Applied;未采用时可以省略该头,并按默认契约返回。异步场景返回 202、任务状态 URI 和可追踪 ID;同步超出等待预算后也应保持可查询的任务状态,而不是让客户端重复提交副作用。

http
POST /v1/imports HTTP/1.1
Prefer: return=minimal, respond-async, wait=3
Idempotency-Key: imp-8f2

HTTP/1.1 202 Accepted
Preference-Applied: respond-async
Location: https://api.example/imports/jobs/42
Cache-Control: no-store

4. 处理缓存变体

如果同一安全 GET 的表示会随 Prefer 改变,响应需要正确声明 Vary,或避免把偏好相关响应放入共享缓存。对写入响应通常使用 no-store;异步状态资源应定义短缓存、ETag 或明确的轮询条件,避免中间层返回过期进度。

5. 保证幂等与降级

Prefer 不改变操作语义,重试仍需遵守幂等性。写入接口使用幂等键或业务去重键;客户端若看到 202、超时或没有 Preference-Applied,应查询任务或按默认响应处理,不能因为偏好未确认就再次创建资源。

6. 设置观测和限界

记录偏好令牌、是否采用、等待时长、响应大小、202 比例和代理链路。限制允许的 wait 范围,拒绝过大的值或将其截断;对未知偏好采用忽略并记录,避免把任意客户端字符串变成昂贵的执行路径。

高质量示范回答

“我会把 Prefer 当作可忽略的客户端偏好,而不是承诺。写入接口默认返回稳定状态;客户端需要轻量响应时发送 return=minimal,需要资源表示时发送 return=representation,长任务使用 respond-async 和受限的 wait。服务器实际采用才返回 Preference-Applied;异步处理返回 202、Location 和任务 ID。写入使用幂等键,响应按安全性设置 no-store,表示差异通过 Vary 或缓存隔离处理。客户端没有 Preference-Applied 时走默认解析并查询任务,绝不因偏好不确定而重复副作用。”

常见错误

  • 把 Prefer 当强制指令 → 服务器或代理可忽略它 → 用默认契约和 Preference-Applied确认。
  • 把 wait 当完成保证 → 长任务仍可能超时 → 限制预算并提供 202 状态资源。
  • 异步超时后再次提交 → 产生重复副作用 → 使用幂等键并先查询任务。
  • 忽略响应变体缓存 → 客户端拿到不匹配的表示 → 设置 Vary 或隔离缓存。
  • 接受任意未知偏好并执行昂贵逻辑 → 攻击者可放大资源消耗 → 未知偏好忽略、记录并限制令牌。

追问及应对

没有 Preference-Applied 是否代表请求失败?

不代表。服务器可能选择默认行为或忽略偏好;客户端应依据稳定默认契约解析响应,只有协议或业务状态明确失败时才判定失败。

return=minimal 能否用于所有写操作?

不能。它只表达客户端不需要完整表示;若客户端必须获得服务器生成的版本号、校验摘要或后续链接,就应请求表示或查询资源,不能从空响应中推断这些字段。

wait=5 是否会让服务器阻塞五秒?

不会构成硬性保证。它表示客户端愿意等待的偏好上限,服务器可更早返回、忽略或转为异步;服务端仍需执行自身超时、并发和资源预算。

公开来源

同类题目