首页/网络/协议速查/406 Not Acceptable 无法满足内容协商
HTTP 方法与状态码91 条

406 Not Acceptable 无法满足内容协商

目标资源存在,但无法产出满足 Accept、Accept-Language 等请求头要求的表示。

协议速查网络更新于 2026-10-13

406 是什么

406 Not Acceptable 表示目标资源确实存在,但服务端根据请求里的内容协商头(Accept、Accept-Language、Accept-Encoding 等)挑不出一种自己能够产出的表示,于是拒绝返回。规范定义在 RFC 9110 第 15.5.7 节。它既不是权限问题也不是路径问题,排查方向应当放在协商头与服务端支持格式的比对上。

基本信息

状态码406 Not Acceptable
语义资源存在,但没有满足协商条件的表示
规范RFC 9110 §15.5.7
触发头Accept / Accept-Language / Accept-Encoding
与缓存关系响应是否能缓存取决于 Vary 声明的分歧维度
重试有无用通常无效,必须换协商头或换请求格式

协商头与失败原因

请求头作用典型失败写法
Accept声明可接受的媒体类型只写自定义类型,服务端当前只支持标准 JSON
Accept-Language声明可接受的自然语言只写 zh-CN,站点当前只提供英文
Accept-Encoding声明可接受的压缩算法只写 br,中间代理与源站只支持 gzip
Accept-Charset历史头,现代多被忽略服务端仍在严格校验该头时会突然报错
Vary响应头,声明按哪些维度区分缓存缺失时不同协商结果互相覆盖,表现为时好时坏

典型使用场景

  • 改版后接口报错:客户端照抄了旧文档里的自定义媒体类型,而服务端已改回标准 JSON
  • 多语言站点只提供部分语种,客户端把未支持的语种硬编码进请求头
  • 压缩协商异常:客户端把 br 当作唯一可接受编码,链路上却有一层只支持 gzip 的老设备
  • 老框架自带严格内容协商逻辑,新增前端路由或更换调用方后开始命中
  • 压测脚本与爬虫伪造了奇怪的 Accept 值,被严格实现直接拒绝

复现与对照排查

复现与对照排查
# 复现:声明一个服务端不支持的媒体类型
curl -si https://api.example.com/report -H 'Accept: application/vnd.super+json'
# HTTP/1.1 406 Not Acceptable
# 对照一:不带 Accept(等价于接受任意类型)
curl -si https://api.example.com/report
# 对照二:只改压缩协商再试
curl -si --compressed -H 'Accept-Encoding: gzip' https://www.example.com/
服务端完全可以忽略 Accept 直接返回默认格式,此时不会出现 406;出现 406 说明这一层确实做了严格校验。定位时同时对比「不带该头」和「带常见值」两次请求,差异就是答案。若经网关访问正常、直连后端才报错,说明是网关做了格式兜底。
别把 406 与 415 混为一谈:406 是「我产不出你要的格式」,415 Unsupported Media Type 是「你发来的请求体格式我不认」。把 406 当成可重试错误会让客户端在重试里反复失败。

易错点

  • 只盯着服务端改实现,不看客户端实际发出的 Accept:默认值常由某个 SDK 或中间代理注入
  • 网关层做了格式与压缩兜底,问题只在直连后端时暴露,本地复现不到就误判为偶发故障
  • 把 406 按 401/403 的思路处理成换凭证,白花排查时间
  • Vary 配置不当导致不同协商结果的响应互相缓存,前端表现为随机拿到错误格式

数据来源与参考

  • RFC 9110 §15.5.7 406
  • RFC 9110 §12 内容协商

相关工具

​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌