如何为apache和nginx服务的所有404页添加无缓存标题?


9

切换到Cloudflare后,我最近遇到了一个问题,解决方案是基本上停止Cloudflare缓存404响应。

在我们的负载均衡的多服务器设置中,偶尔会出现404错误,但它们会通过rsync(通过lsyncd)快速修复。在Cloudflare之前,随着rsync的工作,对404ed文件的重新请求很快就会变成200。

但是,由于Cloudflare基于缓存标头缓存所有数据,而apache和nginx均未发送404的不缓存标头,因此Cloudflare最终将404响应缓存了一段时间。

我一直在寻找一种解决方案,以便在apache和nginx中(全局地,对于所有托管域)为404s全局添加这样的标头,但到目前为止,它还是空白。

有人可以帮忙吗?

谢谢。


相似的问题,虽然仅适用于apache(也仍未得到回答):serverfault.com/questions/331544/…
Artem Russakovskii 2015年

到目前为止,我很确定您不能覆盖apache和nginx中默认404处理程序返回的标头(请证明我错了!)。我能够覆盖404处理程序,并将其指向一个在Apache中发送此类标头的PHP文件,但是由于nginx在我的设置中不支持PHP,因此将“ expires -1;”设置为 在404位置上似乎并没有实际执行任何操作,但我仍然对如何在nginx中执行此操作感到困惑。
Artem Russakovskii 2015年

Answers:


6

您不能使用error_page指令来解决问题,然后使用添加的标头单独处理该位置吗?

例如在Nginx中:

    server {
      ...
      error_page 404 /404.html;
      location = /404.html {
        root   /usr/share/nginx/html;
        add_header Cache-Control "no-cache" always;
      }
    }

1
这里有两个问题,但这就是我的前进方向。1.我不想覆盖默认的404页面,而不必在每个页面中创建规则,listen因为locationhttp直接在内部支持。2.更重要的是,您的代码段实际上不起作用,因为add_header仅适用于20X和30X(nginx.org/en/docs/http/ngx_http_headers_module.html)。但是,我们很幸运,因为从最近发布的1.7.5开始,您现在可以添加一个always修饰符,将其应用于所有响应代码。我必须升级nginx,但这是一个不错的选择。有用。
Artem Russakovskii 2015年

2
我更新了答案,您也许应该添加一个答案,说明您为解决该问题做了什么?
jimmiw

看起来也省略了root工程。如果将其删除,那几乎就是我最终为nginx做的事情。
Artem Russakovskii 2015年

对于apache,我决定实际上要使用自定义页面,所以我这样做了:ErrorDocument 404 /path/to/my/404.php。然后在404.php中,我做了<?php //不缓存404标头(“ Cache-Control:no-cache,must-revalidate”);// HTTP / 1.1标头(“有效期:星期六,1997年7月26日,05:00:00 GMT”);//过去的日期?>
Artem Russakovskii 2015年

我正在将您的答案标记为已接受。如果有人想在以后提供更通用的apache答案,或者是一个在全球范围而不是每个范围server都可以使用的nginx答案,那么他们可能会感到不满。
Artem Russakovskii 2015年

5

您也可以通过这种方式进行操作:

map $status $cache_header {
    default <for_other_codes>;
    404     "no-cache";
}


server {

    [ ... ]

    add_header "Cache-Control" $cache_header always;

}

聪明。我可能会选择其他解决方案,因为它已经可以工作并且不需要每次都指定默认的Cache-Control标头,但这是在框外思考。
Artem Russakovskii 2015年

后面没有分号,404 "no-cache"但是stackexchange的愚蠢的最少6个字符的编辑限制使我无法修复它。显然,对于所有与编码和配置有关的网站而言,这不是一个很好的限制...
nh2

3

在Apache 2.4中,您可以尝试执行以下操作:

FileETag None
<IfModule mod_headers.c>
    Header always unset ETag "expr=%{REQUEST_STATUS} == 404"
    Header always set Cache-Control "max-age=0, no-cache, no-store, must-revalidate" "expr=%{REQUEST_STATUS} == 404"
    Header always set Pragma "no-cache" "expr=%{REQUEST_STATUS} == 404"
    Header always set Expires "Wed, 11 Jan 1984 05:00:00 GMT" "expr=%{REQUEST_STATUS} == 404"
</IfModule>

always之所以重要,是因为这是:

您正在向本地生成的非成功(非2xx)响应(例如重定向)添加标头,在这种情况下,最终响应中仅使用与always对应的表。

您说了所有404,但是为了完全参考,当然可以将其包装在<FilesMatch><LocationMatch>限制范围内。

我相信这是apache 2.4中的一项新功能,因为使用expr条件语句不是mod_headers文档的2.2版本中的。

curl -I [foo] 在没有此配置的情况下进行测试:

HTTP/1.1 404 Not Found
Date: Thu, 24 May 2018 17:44:29 GMT
Server: Apache/2.4.18 (Ubuntu)
Content-Type: text/html; charset=iso-8859-1

curl -I [foo] 使用此配置进行测试:

HTTP/1.1 404 Not Found
Date: Thu, 24 May 2018 17:44:42 GMT
Server: Apache/2.4.18 (Ubuntu)
Cache-Control: max-age=0, no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Content-Type: text/html; charset=iso-8859-1

资料来源:

http://httpd.apache.org/docs/current/mod/mod_headers.html


0

我在这个问题上的五分钱-

在我们的PHP项目中,我们只有404个页面,因此我决定使用PHP header()函数在PHP级别上进行操作

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.