我正在尝试强制缓存一段非常令人讨厌的 PHP 脚本,该脚本通过主动设置所有反缓存标头来主动尝试抵制缓存:
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Content-Type: text/html; charset=UTF-8
Date: Thu, 22 May 2014 08:43:53 GMT
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Last-Modified:
Pragma: no-cache
Set-Cookie: ECSESSID=...; path=/
Vary: User-Agent,Accept-Encoding
Server: Apache/2.4.6 (Ubuntu)
X-Powered-By: PHP/5.5.3-1ubuntu2.3
如果可以避免,我根本不想修改这段第三方代码,而只是让 Apache 缓存页面一段时间。我只会选择性地对特定页面执行此操作,这些页面对会话 cookie 等没有实际影响,即不包含任何个性化信息。
CacheDefaultExpire 600
CacheMinExpire 600
CacheMaxExpire 1800
CacheHeader On
CacheDetailHeader On
CacheIgnoreHeaders Set-Cookie
CacheIgnoreCacheControl On
CacheIgnoreNoLastMod On
CacheStoreExpired On
CacheStoreNoStore On
CacheLock On
CacheEnable disk /the/script.php
Apache 是缓存页面没问题:
[cache:debug] AH00698: cache: Key for entity /the/script.php?(null) is http://example.com:80/the/script.php?
[cache_disk:debug] AH00709: Recalled cached URL info header http://example.com:80/the/script.php?
[cache_disk:debug] AH00720: Recalled headers for URL http://example.com:80/the/script.php?
[cache:debug] AH00695: Cached response for /the/script.php isn't fresh. Adding conditional request headers.
[cache:debug] AH00750: Adding CACHE_SAVE filter for /the/script.php
[cache:debug] AH00751: Adding CACHE_REMOVE_URL filter for /the/script.php
[cache:debug] AH00769: cache: Caching url: /the/script.php
[cache:debug] AH00770: cache: Removing CACHE_REMOVE_URL filter.
[cache_disk:debug] AH00737: commit_entity: Headers and body for URL http://example.com:80/the/script.php? cached.
然而,它总是坚持“缓存的响应不新鲜”,并且从不提供缓存的版本。我猜测这与标头有关Expires
,标头将文档标记为已过期(但我不知道这是否是正确的假设)。我尝试使用 mod_headers 覆盖和取消设置标头,但这没有帮助;无论我尝试哪种组合,缓存都没有留下任何印象。我猜操作顺序是错误的,并且标头正在被重写后缓存可以看到它们。early
标头处理也无济于事。我尝试过CacheQuickHandler Off
并尝试设置显式过滤器链,但没有任何帮助。但我真的只是在摸索,因为我没有太多配置 Apache 过滤器链的经验。
对于如何缓存这段令人讨厌的代码,有没有一个直接的解决方案?
答案1
空的 Last-Modified: 标头使请求无法缓存。因此,首先要做的是生成一个,一种解决方案是使用 php auto_prepend_file
:
创建一个文件prepend.php
,内容如下:
<?php header("上次修改时间:" . gmdate("D, d MYH:i:s"), " GMT"); ?>
然后在您的 vhost 配置中添加指令:php_value auto_prepend_file path_to_prepend.php
此时,您必须验证服务器响应是否具有正确的Last-Modified:
标头。如果没有,我们将无法缓存它;如果是,那么您使用 mod_headers 和 mod_cache 的工作现在可能正在运行?
如果没有的话,你可以像这样使用 squid 和 apache:
Apache 配置
在正确的虚拟主机中,只需启用mod_rewrite
并使用它重定向您想要缓存的流量:
<VirtualHost 你的当前虚拟主机:80> 服务器名称 your.site.com .. RewriteEngine 开启 # 这使得缓存服务器能够将请求视为 http://your.site.com/.. ProxyPreserveHost 开启 # 这应该在 VirtualHost 级别,而不是 <Directory> 或 .htaccess # DoSquid 环境变量决定我们是否将请求发送到缓存服务器 # 根据您的需要进行调整 RewriteRule /the/script.php - [E=DoSquid:Yes] # POST 不可缓存 重写条件 %{REQUEST_METHOD} ^POST$ 重写规则 .* - [E:DoSquid:No] # 随意添加任何符合你需求的规则 # 来自本地主机的请求是来自“主”虚拟主机的调用(见下文) RewriteCond %{REMOTE_ADDR} ^127\.0\.0\.1$ [E:DoSquid:No] RewriteCond %{ENV:DoSquid} ^Yes$ 重写规则 /the/script.php http://ip_of_caching_server/this/script.php [P,L,QSA] .. .. <虚拟主机/> # 您的缓存服务器将访问此 VirtualHost 作为您网站的主服务器 # 端口 8009 可以是任意端口,只要它必须是一个单独的虚拟主机 <VirtualHost 你的当前虚拟主机:8009> 服务器名称 your.site.com .. RewriteEngine 开启 # 这里大量使用 mod_headers 以获得可缓存的响应 # 不用说,这可能会彻底破坏您的应用程序。响应如下 # 完全匿名 标头未设置 Set-Cookie 标头未设置 Etag 标头未设置 Pragma RequestHeader 未设置 Cookie # 现在修复 Cache-Control 标头.. 标头合并 Cache-Control public # max-age 很麻烦。如果未设置,则必须设置一个;如果为 0,则必须更改它 标头合并缓存控制“max-age=bidon” # 当我们有以下情况时:Cache-Control max-age=.., .... 标题编辑缓存控制“^(.*)max-age=(.*)max-age=bidon, (.*)$”$1max-age=$2$3 # 当我们有以下情况时:Cache-Control yyy=bidon,max-age=..” 标题编辑缓存控制“^(.*)max-age=(.*), max-age=bidon$”$1max-age=$2 # 如果没有 max-age,则替换该值,设置为 10mn 标题编辑缓存控制“max-age=bidon”“max-age=600” # 如果 max-age=0,则替换该值,设置为 10mn 标题编辑缓存控制“max-age=0”“max-age=600” # 删除阻止缓存的 Cache-Control 参数 标头编辑缓存控制“no-cache,” “” 标头编辑缓存控制“no-store,” “” 标头编辑 Cache-Control "post-check=0, " "" 标头编辑 Cache-Control "pre-check=0, " "" 标头编辑 Cache-Control“must-revalidate,” “” # 请求现在转发到第一个 vhost。它不会循环,因为我们不缓存来自 127.0.0.1 的请求 ProxyPreserveHost 开启 重写规则 ^(.*)$ http://127.0.0.1/$1 [P,L,QSA] .. .. <虚拟主机/>
缓存服务器配置
您可能可以使用任何东西:squid,apache,varnish。使用 squid 您必须将其配置为反向代理并声明cache_peer your.site.com parent 8009 0 no-query originserver ..
也许您只需mod_cache
在第二个 vhost 中启用即可实现您想要的。