417 Expectation Failed
用法
收到 417 Expectation Failed 错误消息时,说明客户端在请求的 Expect 头中指定了一个或多个用于主动协商的条件。这与信息性的 100 响应相关。
当使用 Expect: 100-continue 头提交请求时,服务器会检查请求的相关细节。这些细节包括 Content-Type 或 Content-Length 头字段。如果服务器愿意接受消息体,则返回信息性的 100 响应。
如果服务器不愿接受消息体,则发送一个恰当的状态,例如 401 或 405。只有当服务器或响应链不支持 expectation 时,才会返回 417 Expectation Failed 错误。若收到此消息,客户端应在不带 Expect 头的情况下重新发送请求。
SEO 影响
像 Google 这样的搜索引擎不会索引响应状态为 417 Expectation Failed 的 URL。此前已被索引的 URL 会从搜索结果中移除。
客户端的特别注意事项
发送 Expect: 100-continue 的客户端无需等待特定的时长。客户端可在未先收到响应的情况下就着手传输消息体。由于 HTTP/1.0 服务器不支持 expectation,当其作为中间节点被使用时,客户端在传输消息体前不会无限期等待。
服务器的特别注意事项
如果服务器收到作为 HTTP/1.0 请求一部分的 Expect: 100-continue,则必须忽略该 expectation。如果消息体已被接收,或不存在消息体,服务器无需以 100 予以确认。
当服务器发送 100 时,最终必须跟随一个最终状态(如 200),除非连接在此之前被断开。
如果服务器在收到完整消息体之前就返回最终响应,该响应会表明服务器打算如何处理连接:关闭连接,或继续读取并丢弃请求消息。
示例
客户端请求发送一个 10K 的 PDF 文件。由于不支持 expectation,服务器返回 417 Expectation Failed。
请求
PUT /docs HTTP/1.1
Host: example.com
Content-Type: application/pdf
Content-Length: 10000
Expect: 100-continue
响应
HTTP/1.1 417 Expectation Failed
Content-Type: text/html
Content-Length: 159
<html>
<head>
<title>Expectations not supported</title>
</head>
<body>
<p>Expectations are not supported by this server.
</p>
</body>
</html>
如何修复
移除 Expect: 100-continue 头,并在包含完整消息体的情况下重新发送请求。说明服务器或某个中间代理不支持 100-continue 机制。
许多 HTTP 客户端库会在没有显式指示的情况下,为大型载荷自动添加 Expect: 100-continue 头。在库级别禁用此行为:
代理和中间节点问题。HTTP/1.0 代理、负载均衡器和较旧的网关不理解 Expect: 100-continue 握手。当请求经过这样的中间节点时,代理会在源服务器处理该 expectation 之前拒绝请求。升级代理或绕过 HTTP/1.0 中间节点可在此类环境中解决问题。
在服务端,此状态在现代 HTTP 栈中很少见。大多数服务器要么遵从 Expect: 100-continue,要么静默忽略该头。返回 417 是要求从请求中移除该 expectation 的有意信号。
代码参考
.NET
HttpStatusCode.ExpectationFailed
Rust
http::StatusCode::EXPECTATION_FAILED
Rails
:expectation_failed
Go
http.StatusExpectationFailed
Symfony
Response::HTTP_EXPECTATION_FAILED
Python3.5+
http.HTTPStatus.EXPECTATION_FAILED
Java
HttpServletResponse.SC_EXPECTATION_FAILED
Apache HttpComponents Core
org.apache.hc.core5.http.HttpStatus.SC_EXPECTATION_FAILED
Angular
@angular/common/http/HttpStatusCode.ExpectationFailed