406 Not Acceptable
用法
收到 406 Not Acceptable 错误时,该响应由 Accept 或 Accept-Language 之类的协商相关头触发。当客户端包含一个或多个这类头时,服务器会在可能的情况下满足这些要求。
最常见的 HTTP Accept 头有:
Accept:指定首选的内容类型。服务器可提供纯文本或 HTML 表示。在本例中,客户端首选 HTML,但也接受纯文本。
Accept: text/html, text/plain
Accept-Encoding:指定客户端接受的编码。在本例中,客户端表明支持 gzip 压缩。
Accept-Encoding: gzip
实践中,此错误很少被使用,因为服务器通常会转而提供一个默认表示。其背后的理念假设客户端宁可要一些东西也不愿一无所获。当确实返回 406 Not Acceptable 响应时,消息体中包含一个可用表示的列表,供客户端从中选择。
注意
406 Not Acceptable 意味着服务器无法生成与客户端 Accept 头匹配的响应(输出格式问题)。415 Unsupported Media Type 意味着服务器无法理解请求体的 Content-Type(输入格式问题)。406 关乎客户端想要接收什么,而 415 关乎客户端发送了什么。
SEO 影响
像 Google 这样的搜索引擎不会索引返回 406 Not Acceptable 状态的 URL。此前已被索引、如今返回该状态码的 URL 会从搜索结果中移除。
示例
客户端请求法语版本的资源,但由于只有德语和英语版本可用,服务器返回 406 Not Acceptable。
请求
GET /news HTTP/1.1
Host: example.com
Accept-Language: fr
响应
HTTP/1.1 406 Not Acceptable
Content-Type: text/html
Content-Length: 242
<html>
<head>
<title>French Language Not Available</title>
</head>
<body>
<p>Please choose a supported language:</p>
<p><a href="/news/news-de.html">German</a></p>
<p><a href="/news/news-en.html">English</a></p>
</body>
</html>
如何修复
406 Not Acceptable 意味着服务器没有任何与客户端内容协商头匹配的表示。
审查 Accept 头。放宽可接受的媒体类型。例如,在 text/html 之外添加 application/json,或使用 / 来接受任何格式。使用浏览器开发者工具(Network 标签页)或 curl -v 检查客户端发送的确切 Accept 头。
检查 Accept-Language 约束。请求服务器不支持的语言会触发此错误。扩大语言列表,或添加通配符(*)作为回退。浏览器语言设置会自动控制该头。可在浏览器的语言首选项中进行调整。
移除过于严格的 Accept-Encoding 或 Accept-Charset 值。狭窄的编码或字符集要求会限制服务器的选择。允许常见值,如 gzip、deflate 和 UTF-8。
检查响应体中的可用替代项。服务器通常会在 406 响应中列出支持的表示。选择其一并相应调整协商头。
检查服务端的内容协商配置。服务器上配置错误的类型映射或缺失的 MIME 类型注册会导致意外的 406 响应。在 Apache 中,mod_negotiation 和 MultiViews 控制类型映射。核实 AddType 指令已注册所需的 MIME 类型。
检查 mod_security 或 WAF 规则。Apache 的 mod_security(及类似 WAF)会拦截请求,并在规则针对请求内容(而非 Accept 头)触发时返回 406。检查服务器错误日志中的 ModSecurity 条目,并记下规则 ID(如 [id “941160”])。将特定规则加入白名单,而不是完全禁用 WAF:
SecRuleRemoveById 941160
将该排除项放入虚拟主机配置或 .htaccess 文件中。
用最简请求进行测试。剥离所有协商头,用 curl 发送一个裸请求,以判断服务器是否返回默认表示。如果裸请求成功,再逐个加回协商头,以隔离出触发拒绝的那个头。
核实 API 版本协商。有些 API 使用 Accept 头进行版本控制(如 application/vnd.api.v2+json)。发送不受支持的版本字符串会产生 406。对照 API 文档确认版本值。
代码参考
.NET
HttpStatusCode.NotAcceptable
Rust
http::StatusCode::NOT_ACCEPTABLE
Rails
:not_acceptable
Go
http.StatusNotAcceptable
Symfony
Response::HTTP_NOT_ACCEPTABLE
Python3.5+
http.HTTPStatus.NOT_ACCEPTABLE
Java
java.net.HttpURLConnection.HTTP_NOT_ACCEPTABLE
Apache HttpComponents Core
org.apache.hc.core5.http.HttpStatus.SC_NOT_ACCEPTABLE
Angular
@angular/common/http/HttpStatusCode.NotAcceptable