工作原理
请求可以携带多个偏好头:Accept 列出媒体类型,Accept-Language 列出语言,Accept-Encoding 列出压缩方案。每个条目可带 0 到 1 的质量值,供服务器排序。服务器选择最佳可用表示,用匹配的 Content-Type 或 Content-Language 返回,并添加 Vary,让缓存按影响选择的请求头建立键。若没有可接受的表示,正确响应是 406 Not Acceptable。
GET /docs/guide HTTP/1.1
Accept: text/html;q=1.0, application/json;q=0.8
Accept-Language: fr-CA, en;q=0.7
Accept-Encoding: br, gzip
服务器也可以忽略偏好返回默认表示,但必须如实标注。
何时使用与取舍
内容协商适合内容平台、国际化站点,以及支持多种媒体类型或版本的 API。它让每个资源保持一个 URL,同时允许客户端选择格式,对可访问性、带宽和本地化都有价值。
代价是每个协商维度都会成倍增加缓存变体。Vary: Accept, Accept-Language, Accept-Encoding 可能严重碎片化 CDN 缓存,规范化请求头或使用独立 URL 往往更高效。质量值容易被误读,真正发送精确偏好的客户端也很少。调试时必须检查请求头,而不只是路径。
示例与误解
常见错误是把 Accept 当成强制要求。客户端请求 XML 而服务器只有 JSON 时,只有在客户端没有禁止 JSON 的情况下返回 JSON 才合法,否则应返回 406。另一个错误是通过 Accept-Language 切换语言,却只缓存一份变体给所有用户。相关概念:HTTP 缓存、API 版本管理、缓存失效。