【发布时间】:2011-04-15 09:53:10
【问题描述】:
如果我想礼貌地拒绝因临时过载而在网站上提供的服务,HTTP 响应 503 Service Unavailable 似乎很合适。规范提到发送带有 503 的 Retry-after 标头。
有什么意义吗? Retry-after 会影响什么吗?浏览器会注意吗?
【问题讨论】:
标签: http http-headers
如果我想礼貌地拒绝因临时过载而在网站上提供的服务,HTTP 响应 503 Service Unavailable 似乎很合适。规范提到发送带有 503 的 Retry-after 标头。
有什么意义吗? Retry-after 会影响什么吗?浏览器会注意吗?
【问题讨论】:
标签: http http-headers
据我所知,没有浏览器会关注Retry-after 标头。代理和缓存可能,但是
显然,一些浏览器现在包含了对Retry-After 的某种程度的支持(尽管支持最多仍然是不确定的)。我并不完全相信在浏览器中这样做的好处。通常,缓存故障被认为是一个坏主意。但是,如果您知道什么时候会再次接受请求,那么告诉客户不会有什么坏处。 (但是,如果您恢复得比预期的要早,那么任何实际尊重标头的程序都应该假设并报告该站点仍然处于关闭状态。)
最明显的好处是,如果标题存在,Googlebot(可能还有其他蜘蛛)似乎会注意标题,这可以防止它在一段时间内取消对页面的索引。
话虽如此...如果添加它是微不足道的,并且您可以对服务何时可用提出合理准确的估计,那就去吧。不过,我不建议您特意去做。无论如何,这只是建议性的,并且将错误的时间放在那里可能会导致比根本不包括标题更多的问题。
【讨论】:
我认为这是一个先有鸡还是先有蛋的问题:目前没有浏览器实现 Retry-after,因为没有网站愿意这样做。我认为,继续将其作为服务发送给用户。如果他们选择的网络浏览器没有实现它,那就是他们的浏览器没有给他们有用的信息。你做到了!
在寻求实现具有多个相互竞争的实现的标准时,我总是尝试遵守这些标准,而不是关注不同的实现(除非我专门尝试模拟一个实现,例如 cURLing 但将我的标题伪装成看起来像一个网络浏览器)。否则,我们最终会得到事实上的标准,如果你还记得你不想要的 IE 主导时代!
【讨论】:
自最初发布此问题以来,客户端和服务器中 Retry-After 标头的实现近年来发生了一些变化。所以我想我会提供一个更新的答案。
首先,RFC 2616,section 14.37 Retry-After 声明:
Retry-After response-header 字段可与 503(服务不可用)响应一起使用,以指示服务预计对请求客户端不可用的时间。
...
它的两个使用例子是
Retry-After: Fri, 31 Dec 1999 23:59:59 GMT Retry-After: 120在后一个示例中,延迟为 2 分钟。
以下是关于各种软件中的 Retry-After 标头的代码存储库提交消息、公告和文档。
2012 年 11 月 22 日的代码提交,日志消息如下: Added detection timeouts and usage of Retry-After HTTP header.
2012 年 3 月 27 日的代码提交,日志消息为:Implement Handling of 5xxs, X-Weave-Backoff, Retry-After。此外,他们的 Mercurial 存储库中有 three other mentions of Retry-After header。
最初于 2004 年 1 月 6 日提交了一个错误,标题为 Retry-After sent with HTTP 503 response is ignored。
一篇关于处理网站停机时间的 Google 网站管理员中心博客文章提到 Retry-After header may be used to determine when to recrawl the URL。
找不到任何官方的 Retry-After 支持文档。但是,随机论坛中提到了一些关于在 503 响应中使用此标头来限制 Microsoft 机器人的内容。
如果响应代码等于 200、201、204、206、301、302、303、304 或 307,则将指定字段添加到响应标头。
因此,使用版本为 503 响应添加 Retry-After 标头:
1.7.4 及更早版本,使用第三方模块,例如Headers More。
1.7.5 及更高版本,将always 参数附加到add_header 指令。
与 Nginx 不同,Apache header documentation 没有表明它不能在 503 响应上发送 Retry-After 标头。然而,关于非 2xx 响应,文档声明:
在本地生成的非成功(非2xx)响应中添加header,例如重定向,在这种情况下,最终响应中只使用always对应的表。
这是一个SO answer,它为 503 响应设置了带有 always 条件的 Retry-After 标头,正如文档所建议的那样。
AskApache 文章提供了其他配置示例,说明如何使用带有 Retry-After 标头的 503 响应 instruct search engines to come back。
我编写了一个 Ruby 服务器,它只返回一个 503 响应,其中 Retry-After 标头设置为 10 秒,正文包含一个随机数。
require 'sinatra'
get '/' do
headers 'Content-Type' => 'text/plain', 'Retry-After' => '10'
status 503
body rand(1000).to_s
end
我在以下时间访问它:
我希望这些浏览器会在 10 秒后自动刷新 URL 并显示一个新的随机数。但是,所有浏览器都没有重试,即使在几分钟后。我也尝试了更短和更长的 Retry-After 周期,结果相同。服务器访问日志确认没有从任何这些浏览器进行过重试。
此外,在 Retry-After 期间之前的“软”刷新会立即重新获取 URL。因此,Retry-After 标头不能用于限制“刷新快乐”的用户。我之所以提到这一点,是因为我在某个论坛上看到此标头可用于阻止不耐烦的用户对您的网站进行攻击。
附带说明,“软”刷新在超时期限之前没有任何操作似乎是合乎逻辑的,但“硬”或缓存绕过刷新会忽略任何超时并立即重新获取 URL。
对 Retry-After 标头的支持在客户端和服务器上似乎仍然有点粗略。尽管如此,如果不难配置,最好为 503 响应设置重试超时。
即使 Googlebot 是唯一支持标头并在超时期限后实际重试的客户端,它也可能会阻止您的网页被取消索引 - 而不是 404、500、502 或 504 响应。
【讨论】:
如果您想在 X 时间后发送自动刷新,您可以发送一个
Refresh: 120; url=http://your_url.com
在 PHP 中:
header("Refresh: " .$retry_time."; url=". $url);
要刷新当前页面,您可以将$_SERVER["REQUEST_URI"] 用于$url。
我在不同版本的 Opera、Firefox 和 Internet Explorer 中成功测试了这个头文件。
此标头甚至可以刷新二进制内容,如图像(但仅当直接加载或在框架中加载时 - IMG-Tag 不会重新加载)。
【讨论】:
Refresh 标头作为完全刷新,如果只是 HTML 文档包含此标头,则所有图像、CSS 等也将始终重新加载。