如何让Apache上的静态内容被浏览器缓存,并且不需要每次请求都检查更新时间?

47

我该如何使Apache上的静态内容被浏览器缓存,而不是每次请求时都检查是否过期?

我正在处理托管在Apache Web服务器上的网站。最近,我尝试使用头文件(Content-Type用于不同类型的内容)进行测试,并发现了很多针对图像的条件请求。例如:

200 /index.php?page=1234&action=list
304 /favicon.ico
304 /img/logo.png
304 /img/arrow.png
(etc.)

虽然图片文件是静态内容并且由浏览器缓存,但每次用户打开链接到它们的页面时,它们会被有条件地请求,并发送“304未修改”状态码。 这样做很好(传输的数据更少),但意味着每次页面加载都要进行20多个以上的请求(由于所有这些往返导致页面加载时间更长,即使启用了Keep-Alive和pipelining)。

我该如何告诉浏览器保留现有文件并不检查更新版本?

编辑:mod_expires方法有效,即使是对于网站图标也可以。

4个回答

62

Apache中的Expires模块可以解决这个问题。

a2enmod expires

需要在服务器配置中加载,并在.htaccess(或服务器配置)中进行设置。

通过Expires头,资源仅在第一次请求时被请求。在到期日期之前,后续请求将从浏览器缓存中满足。在指定的时间过期并且需要该资源时,才会再次请求它(有条件地 - 未更改的资源将返回304)。在到期之前手动清除缓存是唯一可靠的方法,或者强制刷新(通常是Ctrl-F5)。 (如果资源在此期间更改,则可能存在问题,但静态图像很少更改。)

# enable the directives - assuming they're not enabled globally
ExpiresActive on

# send an Expires: header for each of these mimetypes (as defined by server)
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"

# css may change a bit sometimes, so define shorter expiration
ExpiresByType text/css "access plus 1 days"

对于favicon.ico,需要做更多的工作(Apache通常不识别Windows图标文件,并将其发送为默认的text/plain格式)。

# special MIME type for icons - see http://www.iana.org/assignments/media-types/image/vnd.microsoft.icon
AddType image/vnd.microsoft.icon .ico
# now we have icon MIME type, we can use it
# my favicon doesn't change much
ExpiresByType image/vnd.microsoft.icon "access plus 3 months"

瞧,神奇的事情发生了,It Works™!


1
我已经指定了我的网站图标的MIME类型为“image/x-icon”,但似乎无法让Apache设置它的过期头信息。这是为什么?我需要使用“image/vnd.microsoft.icon”吗? - Tom
1
@Tom:“.ICO文件的官方IANA注册MIME类型是image/vnd.microsoft.icon。”(维基百科)所以,你不需要使用它,但这是正确的MIME类型 - 你会用“image/x-jpg”来发送JPEG图像,而不是标准的“image/jpeg”吗?你不想返回正确的MIME类型有技术上的原因吗? - Piskvor left the building
1
@Tom:对于第一个问题,只要服务器知道这个 MIME 类型就可以了,服务器不应该关心它是什么。你的 AddType 是否在此 MIME 类型的 ExpiresByType 前面? - Piskvor left the building
1
请查看《HTTP权威指南》第7章7.83节“服务器重新验证”。书籍链接:http://www.amazon.com/HTTP-Definitive-Guide-David-Gourley/dp/1565925092。 - huangli
如果您需要仅针对特定图像打破缓存,请在图像请求的末尾添加?unique_id,例如mylittlepony.png?25130970942。 - Bluebaron
显示剩余4条评论

34

使用 filesMatch 指令,而不是 ExpiresByType,你可以通过匹配 subtype(例如 image/*)来分组 Content-Type,而不是列出每个 type/subtype 组合,不包括 subtype(例如 image/jpegimage/png)。

#Set caching on image files for 11 months
<filesMatch "\.(ico|gif|jpg|png)$">
  ExpiresActive On
  ExpiresDefault "access plus 11 month"
  Header append Cache-Control "public"
</filesMatch>
根据这篇Google文章,我设置了过期时间不超过1年(access plus 11 month)并添加了Cache-Control "public"以启用Firefox的HTTPS缓存。

对于CSS和JS,Google建议将过期时间设为1周。

<filesMatch "\.(css|js)$">
  ExpiresActive On
  ExpiresDefault "access plus 1 week"
  Header append Cache-Control "public"
</filesMatch>

1
我非常喜欢这个答案。谢谢分享! - KyleFarris
如果我需要检查 '<IfModule mod_headers.c>',嵌套指令是否可以? - Rantiev

3
如果您在静态图像的http响应中设置了Expires头,则在第一次下载后,直到指定的时间过去之前,不会再次检查服务器上的该图像,例如,如果我现在从您的服务器下载一个文件,则其Expires头将是:
Expires: Fri, 1 Jan 2010 00:00:01 GMT 

如果我不清除缓存或进行强制刷新(在 Windows 上按 Ctrl+F5),那么我的浏览器将不会再次从您的服务器查找该内容,直到2010年。这里有一个简单的设置说明,可以在这里找到,并且其他可能有用的响应列表可在维基百科上找到。

2

关于favicon.ico,将其放在您的服务器文档根目录中,比如/var/www/html,并在/etc/httpd/conf/httpd.conf的别名部分添加以下内容:

Alias /favicon.ico "/var/www/html/favicon.ico"
<Directory "/var/www/html">
    <Files favicon.ico>
       ExpiresActive On
       ExpiresDefault "access plus 1 month"
    </Files>
</Directory>

如果您将favicon.ico设置为别名,则单个favicon.ico将适用于所有虚拟托管站点。用户访问您的网站后,任何进一步的访问都将从浏览器缓存副本中获取,而不是从网络中获取,有效期为一个月。

我无法理解。

ExpiresByType image/ico "access plus 1 month"

要使其正常工作,也许需要像上面建议的那样将其类型设置为text/plain。无论如何,ExpiresDefault都能正常工作。


关于全局favicon的好处,如果您不介意所有站点共享同一个图标,那么这是个不错的点子。请参考我的回答中有关image/ico的内容:1)image/ico不是正确的MIME类型,2)您需要定义image/vnd.microsoft.icon - 它不是Apache预定义的。 - Piskvor left the building

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