当PHP动态创建HTTP响应时,如何缓存它们?

14

我认为我的问题看起来很普通,但请耐心听我说,因为它变得有趣了(至少对我来说是这样的)。

考虑一个用途是从文件系统读取请求文件并将其作为响应输出的 PHP 页面。现在的问题是如何为此页面启用缓存?需要指出的是,这些文件可能非常大,启用缓存是为了使客户端免于不断下载相同的内容。

理想的策略是使用 "If-None-Match" 请求头和 "ETag" 响应头来实现反向代理缓存系统。即使我知道到这一步,我也不确定是否可能或者我应该返回什么响应以实现这种技术!


酷炫的眼睛。但还是比不上我的。 - Madara's Ghost
别这么肯定,这只眼睛的主人现在是十尾人柱力! - Mehran
目前为止,我的王牌还没有被揭示出来。让我们在Anime & Manga chat上继续这个聊天,以免混乱这个线程。 - Madara's Ghost
我已经在这里了,但问题是我几乎没有时间发布任何东西。抱歉。 - Mehran
1个回答

25

使用PHP来服务大量或大型辅助文件并不是它的强项。

相反,对于nginx,可以查看X-accel,对于Lighttpd则是X-Sendfile,而Apache则是mod_xsendfile

最初的请求由PHP处理,但一旦下载文件已确定,它将设置一些标头以指示服务器应该处理文件发送,此后PHP进程被释放以提供其他服务。

然后,您可以使用Web服务器为其配置缓存。

静态生成的内容

如果您的内容是从PHP生成的,并且特别耗费资源,请将输出写入本地文件并再次应用上述方法。

如果您无法写入本地文件或不想写入,则可以使用HTTP响应标头来控制缓存:

Expires: <absolute date in the future>
Cache-Control: public, max-age=<relative time in seconds since request>

这将导致客户端缓存页面内容,直到页面过期或用户强制重新加载页面(例如按下F5键)。

动态生成的内容

对于动态内容,您希望浏览器每次都向您发出请求,但仅在有新内容时才发送页面内容。您可以通过设置其他一些响应头来实现这一点:

ETag: <hash of the contents>
Last-Modified: <absolute date of last contents change>
当浏览器再次调用您的脚本时,它们将依次添加以下请求头:
If-None-Match: <hash of the contents that you sent last time>
If-Modified-Since: <absolute date of last contents change>

ETag主要用于减少网络流量,因为在某些情况下,为了知道内容的哈希值,您首先必须计算它。

如果您有本地文件缓存(文件有修改日期),则最容易应用Last-Modified。一个简单的条件就可以使其工作:

if (!file_exists('cache.txt') || 
    filemtime('cache.txt') > strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
    // update cache file and send back contents as usual (+ cache headers)
} else {
    header('HTTP/1.0 304 Not modified');
}

如果你无法使用文件缓存,你仍然可以使用ETag来确定内容是否在此期间发生了更改。


ping是如何工作的?我的意思是,当客户端请求页面时,我没有看到任何HTTP_IF_MODIFIED_SINCE变量,并且在提供文档时我已经设置了ETAG。因为这不起作用,我设计了另一种方法,使用ajax“ping”服务器并请求版本号。如果版本号与页面不同,则通过window.location.reload(true)重新加载以强制请求。当缓存所有内容部分(例如css和js)时,只需要一个请求来检查差异,而不是很多“304未修改”的响应。也许它依赖于JS,但运行良好。 - Codebeat
那就是我正在使用的,不过谢谢你的评论。- header('If-None-Match: '.$ETag ); - Codebeat
@Erwinus 嗯,If-None-Match 是一个请求头,而不是响应头,哈哈; 你应该在响应中设置 ETag: value :) - Ja͢ck
@Jack:好的谢谢伙计,但请注意评论要友好,不是每个人都像你这么聪明。;-P现在它可以工作了,谢谢。 - Codebeat
@Erwinus,我在我的回答中更明确地说明了它们是哪种类型的标头。感谢您的反馈。 - Ja͢ck
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接