web网页图片缓存设置方法.htaccess方式

11 年 ago jony web网页图片缓存设置方法.htaccess方式已关闭评论

WordPress博客里大量的图片会使页面加载速度变得缓慢。 此时访问者需要用更多时间才能打开一个页面。 不过我们可以通过缓存图片来解决这个问题。 当页面第一次被加载时,将所有图片存放在浏览器的缓存池里。 之后访问者再加载该页面时,浏览器就可以从浏览器缓存中获取图片,从而减少页面加载时间。

对Apache服务器上的WordPress博客/网站,可以通过编辑根目录下的.htaccess文件来激活图片缓存功能。 浏览器能够简单读取.htaccess文件的缓存控制头,而缓存头会要求浏览器将图片或其它任何媒体保留2周时间(或者更久),这样浏览器就能够随时调用 图片,直到图片过期。 两周后浏览器重新将过期的图片存入缓存。 万一浏览器缓存被清空,浏览器会从缓存中重新加载图片或其它媒体。

下面就是对如何在WordPress博客/网站上激活图片缓存的过程详解。

如果你希望提高网站的运行效率,就应该启用网络服务器上的图片缓存功能。 详细步骤如下:
注意:做任何改动前请先备份网站数据域.htaccess文件。

1. (在FTP中)打开根目录下的.htaccess文件
2. 在.htaccess文件中加入如下代码:

   1: # Image and Flash content Caching for One Month
   2: <FilesMatch ".(flv|gif|jpg|jpeg|png|ico|swf)$">
   3: Header set Cache-Control "max-age=2592000"
   4: </FilesMatch>

3. 编辑完毕后保存文件。 代码中“max-age”参数的值为2592000(秒),因此图片缓存和Flash内容缓存在浏览器中保留一个月。

如果这个方法能够奏效,你的网站访问速度将会有很大改善。

下面是一些关于缓存的知识,不嫌长可看:

缓存位于 服务器之间,客户端之间
根据请求保存输出内容的副本,如html页面,图片,文件,当下一个请求来到时,如果相同的URL,直接使用副本响应访问请求,而不向源服务器再次发送请求。

使用缓存的优点
让网站运行的更快
.减少延迟,  从缓存服务器而不是源服务器,过程耗时少,
.减少网络带宽消耗 ,副本被重用,减低客户端的带宽消耗;客户可以节省带宽费用,控制带宽的需求,更易管理。

缓存的类型

1.浏览器缓存
新一代的Web浏览器,都能在设置中发现关于缓存的设置,通过在电脑硬盘存储已经看过的网站的副本。

规则
在同一个会话过程中(在当前浏览器没有被关闭之前)会检查一次并确定缓存的副本足够新。
如果浏览过程中访问到同一个图片,这些图片可以从浏览器缓存中调出而即时显现。

2.代理服务器缓存
Web代理服务器使用同样的缓存原理,代理服务器群为成百上千用户服务使用同样的机制;

代理服务器缓存是共享缓存,为大量用户使用,因此在减少相应时间和带宽使用方面很有效,同一个副本会被重用多次。

3.网关缓存
也称为反向代理缓存或间接代理缓存
网关缓存也是一个中间服务器,和内网管理员部署缓存用于节省带宽不同:网关缓存一般是网站管理员自己部署:让他们的网站更容易扩展并获得更好的性能;
请求有几种方法被路由到网关缓存服务器上:其中典型的是让用一台或多台负载均衡服务器从客户端看上去是源服务器;

网络内容发布商 (Content delivery networks CDNs)分布网关缓存到整个(或部分)互联网上,并出售缓存服务给需要的网站,Speedera 和Akamai ,BT 就是典型的网络内容发布商(下文简称CDN)。

怎样配置服务器的内容将被如何缓存

CDN的网关缓存为希望被缓存的网站服务
如果良好地规划了的网站,缓存会有助于网站服务更快,并节省服务器负载和互联网的链接请求。
这个改善是显著的:有缓存的网站页面几乎是即时显现:用户更喜欢速度快的网站并更经常的访问;

代理服务器和浏览器都回启用缓存,会按照缺省或者缓存管理员的策略进行缓存。

缓存如何工作
规则在协议中有定义(HTTP协议1.0和1.1),一些规则由缓存的管理员设置(浏览器的用户或者代理服务器的管理员);

基本的规则

如果响应头信息:告诉缓存器不要保留缓存,缓存器就不会缓存相应内容;
如果请求信息是需要认证或者安全加密的,相应内容也不会被缓存;
如果在回应中不存在校验器(ETag或者Last-Modified头信息),缓存服务器会认为缺乏直接的更新度信息,内容将会被认为不可缓存。

一个缓存的副本如果含有以下信息,内容将会被认为是足够新的
含有完整的过期时间和寿命控制头信息,并且内容仍在保鲜期内;
浏览器已经使用过缓存副本,并且在一个会话中已经检查过内容的新鲜度;
缓存代理服务器近期内已经使用过缓存副本,并且内容的最后更新时间在上次使用期之前;
够新的副本将直接从缓存中送出,而不会向源服务器发送请求;
如果缓存的副本已经太旧了,缓存服务器将向源服务器发出请求校验请求,用于确定是否可以继续使用当前拷贝继续服务;

总之:新鲜度 和校验 是确定内容是否可用的最重要途径:
如果副本足够新,从缓存中提取就立刻能用了;
而经缓存器校验后发现副本的原件没有变化,系统也会避免将副本内容从源服务器整个重新传输一遍。

如何控制缓存
有很多工具可以帮助设计师和网站管理员调整缓存服务器对待网站的方式,需要下手对服务器的配置进行一些调整,但绝对值得;

HTML meta标签和HTTP 头信息
HTML 文档的<HEAD>区域中 描述文档的各种属性,这些META标签常常被用于标记文档不可以被缓存或者标记多长时间后过期;

HTTP头信息发送在HTML代码之前,只有被浏览器和一些中间缓存能看到,一个典型的HTTP 1.1协议返回的头信息看上去像这样:

HTTP/1.1 200 OK
Date: Fri, 30 Oct 1998 13:19:41 GMT
Server: Apache/1.3.3 (Unix)
Cache-Control: max-age=3600, must-revalidate
Expires: Fri, 30 Oct 1998 14:19:41 GMT
Last-Modified: Mon, 29 Jun 1998 02:28:12 GMT
ETag: “3e86-410-3596fbbc”
Content-Length: 1040
Content-Type: text/html

Pragma HTTP头信息
HTTP头信息中Pragma: no-cache 并不一定会让内容无法被缓存,HTTP的规范中,响应型头信息没有任何关于Pragma属性的说明,而讨论了的是请求型头信息 Pragma属性(头信息也由浏览器发送给服务,集中缓存服务器大部分不会用这个参数。

用了Pragma也不起什么作用,要用下列头信息:
Expires(过期时间)HTTP头信息来控制保鲜期
Expires(过期时间) 属性是HTTP控制缓存的基本手段,这个属性告诉缓存器:相关副本在多长时间内是新鲜的。过了这个时间,缓存器就会向源服务器发送请求,检查文档是否被修改。几乎所有的缓存服务器都支持Expires(过期时间)属性;

可以设计一个绝对时间间隔:基于客户最后查看副本的时间(最后访问时间)或者根据服务器上文档最后被修改的时间;
Expires头信息对于设置静态图片缓存特别有用,这些图片修改很少,可以给它们设置一个特别长的过期时间,这会使网站对用户变得相应非常快;

HTTP的日期时间必须是格林威治时间(GMT),而不是本地时间

Expires: Fri, 30 Oct 1998 14:19:41 GMT
要确认Web服务器时间设置正确,一个途径是通过网络时间同步协议(Network Time Protocol NTP)

过期时间属性局限
.牵扯到了日期,Web服务器的时间和缓存服务器的时间必须是同步的,如果不同步,要么应该缓存的内容提前过期了,要么过期没及时更新。
.如果过期时间是一个固定的时间,返回内容的时候又没有连带更新下次过期的时间,那么之后所有访问请求都会被发送给源Web服务器,反而增加了负载和响应时间;

Cache-Control HTTP头信息
HTTP 1.1 另外一组头信息属性:Cache-Control响应头信息,让网站的发布者控制他们的内容,并定位过期时间的限制。

max-age =[秒]
执行缓存的最长时间,[秒]是一个数字,单位是秒:从请求时间开始到过期时间之间的秒数。

s-maxage =[秒]
类似于max-age属性,除了他应用于共享(如:代理服务器)缓存

public
标记认证内容也可以被缓存,一般来说: 经过HTTP认证才能访问的内容,输出是自动不可以缓存的;
no-cache
强制每次请求直接发送给源服务器,而不经过本地缓存版本的校验。这对于需要确认认证应用很有用(可以和public结合使用),或者严格要求使用最新数据的应用(不惜牺牲使用缓存的所有好处);

no-store
强制缓存在任何情况下都不要保留任何副本
must-revalidate
告诉缓存必须遵循所有你给予副本的新鲜度的,HTTP允许缓存在某些特定情况下返回过期数据,指定了这个属性,高速缓存,希望严格的遵循你的规则。
proxy-revalidate
和 must-revalidate类似,除了他只对缓存代理服务器起作用
举例:
Cache-Control: max-age=3600, must-revalidate

校验参数和校验
校验是当副本已经修改后,服务器和缓存之间的通讯机制;

缓存服务器可以避免副本实际上仍然足够新的情况下重复下载整个原件。
如果不存在,并且没有任何信息说明保鲜期(Expires或Cache-Control)的情况下,缓存将不会存储任何副本;

最常见的校验参数是文档的最后修改时间,通过最后Last-Modified头信息可以,当一份缓存包含Last-Modified信息,他基于此信息,通过添加一个If-Modified-Since请求参数,向服务器查询这个副本从上次查看后是否被修改了。

HTTP 1.1 另外一个校验参数: ETag
服务器生成的唯一标识符ETag,每次副本的标签都会变化。
由于服务器控制了ETag如何生成,缓存服务器可以通过If-None-Match请求的返回没变则当前副本和原件完全一致。

所有的缓存服务器都使用Last-Modified时间来确定副本是否够新,而ETag校验正变得越来越流行;
所有新一代的Web服务器都对静态内容自动生成ETag和Last-Modified头信息,而不必做任何设置。
但服务器对于动态内容(例如:CGI,ASP或数据库生成的网站)并不知道如何生成这些信息

创建利于缓存网站的窍门

保持URL稳定
这是缓存的金科玉律,如果在不同的页面上,给不同用户或者从不同的站点上提供相同的内容,应该使用相同的URL,这使网站缓存友好简单,最高效

使用一个共用的库 存放每页都引用的图片和其他页面元素;
对于不经常改变的图片/页面启用缓存 ,并使用Cache-Control: max-age属性设置一个较长的过期时间;

对于定期更新的内容 设置一个缓存服务器可识别的max-age属性或过期时间;
万不得已不要改变文件 ,否则你会提供一个非常新的Last-Modified日期;例如:当你更新了网站,不要复制整个网站的所有文件,只上传你修改的文件。

只在必要的时候使用Cookie ,cookie难被缓存,大多数情况下不必要;
少用SSL ,加密的页面不会被任何共享缓存服务器缓存,在SSL页面上减少图片的使用;

编写利于缓存的脚本
脚本缺省不会返回校验参数(Last-Modified或ETag头信息)或其他新鲜度信息(Expires或Cache-Control),

如果脚本生成的输出在未来一段时间(几分钟或者几天)都是可重复复制的,那么就是可缓存的。如果脚本输出内容只随URL变化而变化,也是可缓存的;但如果输出会根据cookie,认证信息或者其他外部条件变化,则还是不可缓存的。

最利于缓存的脚本就是将内容改变时导出成静态文件,Web服务器可以将其当作另外一个网页并生成和试用校验参数,让一些都变得更简单,只需要写入文件即可,这样最后修改时间也有了;

对一段时间内能保持较新的内容设置一个相对寿命的头信息,用Cache-Control: max-age属性,它会让首次请求后一段时间内缓存保持新鲜;

对 If-Modified-Since 和/或If-None-Match请求作出反应,这些属性可以从解析HTTP头信息得到,并对符合条件的内容返回304 Not Modified(内容未改变),这种做法比不上前2种高效;

其他窍门:
尽量避免使用POST,POST模式的返回内容不会被大部分缓存服务器保存,如果你发送内容通过URL和查询(通过GET模式)的内容可以缓存下来供以后使用;
尽量不要在URL中加入针对每个用户的识别信息

不要统计一个用户来自一个地址的所有请求,因为缓存常常是一起工作的;
生成并返回Content-Length头信息,如果方便的话,这个属性让你的脚本在可持续链接模式时:客户端可以通过一个TCP/IP链接同时请求多个副本,而不是为每次请求单独建立链接,这样你的网站相应会快很多;

网站缓存的要点
内容热门,大量的复制(特别是图片),对这些内容先部署缓存。

如何让页面通过缓存达到最快相应?
缓存最好的副本是那些可以长时间保持新鲜的内容;
基于校验虽然有助于加快相应,但是它不得不和源服务器联系一次去检查内容是否够新,如果缓存服务器上就知道内容是新的,内容就可以直接相应返回了。

页面是密码保护的,代理缓存服务器如何处理他们?
缺省的,网页被HTTP认证保护的都是私密内容,它们不会被任何共享缓存保留。但是,你可以通过设置Cache-Control: public让认证页面可缓存,HTTP 1.1标准兼容的缓存服务器会认出它们可缓存。
如果你认为这些可缓存的页面,但是需要每个用户认证后才能看,可以组合使用Cache-Control: public和no-cache头信息,高速缓存必须在提供副本之前,将将新客户的认证信息提交给源服务器

Cache-Control: public, no-cache

无论如何:这是减少认证请求的最好方法,例如: 你的图片是不机密的,将它们部署在另外一个目录,并对此配置服务器不强制认证。这样,那些图片会缺省都缓存。

图片设置了1个月后过期,但是现在需要现在更新。

过期时间是绕不过去的,除非缓存空间不足才会删除副本,缓存副本在过期之间会被一直使用。
最好的办法是改变它们的链接,这样,新的副本将会从源服务器上重新下载。

引用它们的页面本身也会被缓存。
因此,使用静态图片和类似内容是很容易缓存的,而引用他们的HTML页面则要保持非常更新;

如果你希望对指定的缓存服务器重新载入一个副本,可以强制使用“刷新”(在FireFox中在reload的时候按住shift键:就会有前面提到Pragma: no-cache头信息发出)。或者你可以让缓存的管理员从他们的界面中删除相应内容;

apahe,可以使用.htaccess文件并提供相应的文档;

可以考虑在各种虚拟主机上建立各种缓存策略
例如: 可以设置一个目录 /cache-1m 专门用于存放访问1个月的访问,
另外一个 /no-cache目录则被用提供不可存储副本的服务。
无论如何:对于大量用户访问还是应该用缓存。对于大网站,这方面的节约很明显(带宽和服务器负载);

缓存服务器并不会总保存副本并重用副本;
他们只是在特定情况下会不保存并使用副本。所有的缓存服务器都回基于文件的大小,类型(例如:图片 页面),或者服务器空间的剩余来确定如何缓存。你的页面相比更热门或者更大的文件相比,并不值得缓存。

Apache HTTP服务器
Apache有些可选的模块来包含这些头信息: 包括Expires和Cache-Control

运行httpd -l 会列出可用的模块,我们需要用的模块是mod_expires和mod_headers

Apache一旦启用了相应的模块,就可以在.htaccess文件或者在服务器的access.conf文件中通过mod_expires设置副本什 么时候过期。
可设置过期从访问时间或文件修改时间开始计算,并且应用到某种文件类型上或缺省设置。

.htaccess文件允许web发布者使用命令只在配置文件中用到的命令。他影响到所在目录及其子目录;问一下你的服务器管理员确认这个功能是否启用了。
### 启用 mod_expires
ExpiresActive On
### 设置 .gif 在被访问过后1个月过期。
ExpiresByType image/gif A2592000
### 其他文件设置为最后修改时间1天后过期
### (用了另外的语法)
ExpiresDefault “modification plus 1 day”
### 在index.html文件应用 Cache-Control头属性
<Files index.html>
Header append Cache-Control “public, must-revalidate”
</Files>
注意: 在适当情况下mod_expires会自动计算并插入Cache-Control:max-age 头信息
Apache 2.0的配置和1.3类似,更多信息可以参考2.0的mod_expires 和mod_headers文档 ;

缓存机制的实现:服务器端脚本
需要注意的一点是:也许服务器设置HTTP头信息比脚本语言更容易,但是两者你都应该使用。
因为服务器端的脚本主要是为了动态内容,他本身不产生可缓存的文件页面,即使内容实际是可以缓存的。如果你的内容经常改变,但是不是每次页面请求都改变,考虑设置一个Cache-Control: max-age头信息;
大部分用户会在短时间内多次访问同一页面。例如:用户点击“后退”按钮,即使没有新内容,他们仍然要再次从服务器下载内容查看。

CGI程序
CGI脚本是生成内容最流行的方式之一,你可以很容易在发送内容之前的扩展HTTP头信息;大部分CGI实现都需要你写 Content-Type头信息
“Cache-Control: max-age=600\n”;
这样脚本可以在被请求后缓存10分钟;这样用户如果按“后退”按钮,他们不会重新提交请求;
CGI的规范同时也允许客户端发送头信息,每个头信息都有一个‘HTTP_’的前缀;这样如果一个客户端发送一个If-Modified-Since请求,就是这样的:

HTTP_IF_MODIFIED_SINCE = Fri, 30 Oct 1998 14:19:41 GMT

SSI(经常使用.shtml扩展名)是网站发布者最早可以生成动态内容的方案。通过在页面中设置特别的标记,也成为一种嵌入HTML的脚本;
大部分SSI的实现无法设置校验器,于是无法缓存。但是Apache可以通过对特定文件的组执行权限设置实现允许用户设置那种SSI可以被缓存;结合XbitHack调整整个目录

PHP
PHP是一个内建在web服务器中的服务器端脚本语言,当做为HTML嵌入式脚本,很像SSI,但是有更多的选项,PHP可以在各种Web服务器上设置为CGI模式运行,或者做为Apache的模块;

<?php
Header(“Cache-Control: must-revalidate”);
$offset = 60 * 60 * 24 * 3;
$ExpStr = “Expires: ” . gmdate(“D, d M Y H:i:s”, time() + $offset) . ” GMT”;
Header($ExpStr);
?>

五种常用于控制客户端缓存的头标

Last-Modified (最后修改时间)
ETag (实体标签)
Expires (有效指示)
Pragma (编译指示)
Cache-Control (缓存控制)

1.Last-Modified

这 个头标是一个响应头标,表示客户端(通常指浏览器)所请求资源在服务器端的最后修改时间,通常情况下客户端在接受这个头标后,在以后对这个资源的请求会附 带一个’If-Modified-Since’请求头标,而这个头标是想告诉服务器上次客户端所请求资源的最后修改时间,对于一些图像,css,js等静 态文件资源,配置好了的apache服务器会理解这些If-Modified-Since请求头标,将头标里的时间和文件的最后修改时间进行比较并作出响 应,如果二者相等则发送一个304 Not Modfied来告诉客户端所请求资源并未修改让客户端放心使用缓存中的资源,否则的话会重新发送一个新的资源和新的Last-Modified的头标。 但是对于一个动态的PHP脚本,我们即使在脚本加入了header(‘Last Modified: ‘.$time)来发送一个Last Modified响应头标,当客户端附带’If-Modified-Since’在次请求时apache服务器不会进行处理,这需要我们自己 用$_SERVER['HTTP_IF_MODIFIED_SINCE']来获取’If-Modified-Since’的值自己来进行判断处理。

2.ETag

ETag(Entity Tag)和Last-Modified类似,也是WEB服务器和客户端用于确认缓存组件的有效性的一种机制,apache 1.3和2.0的ETag格式是inode-size-timestamp,因此当资源被修改,其ETag也发生改变,ETag相对Last- Modified更精确,Last-Modified只能精确的s级别,但是ETag在多服务器可能造成混乱,所以用还是不用还得看实际情况,其相对应的 后续请求头标为If-None-Match。

3.Expires

Expires表明缓存何时因该过期(GMT时间),属于HTTP 1.0 标准,通常是用来对Cache-Control的max-age的一个补充,来兼容HTTP 1.0,不赞成单独使用Expires,因为客户端时间容易发生偏差。

4.Pragma

HTTP 1.0 标准,通常是在不缓存时使用,Pragma: no-cache。

5.Cache-Control

Cache-Control常用指令(暂时我还没找到完整版本的)

public 可以在任何地方缓存
private 只能被浏览器缓存
no-cache 不能在任何地方缓存
must-revalidate 缓存必须检查跟新版本
proxy-revalidate 代理缓存必须检查跟新版本
max-age 内容能够被缓存的时间
s-maxage 覆盖共享缓存的max-age设置

浏览器行为影响

在先前有效访问后,在以后对同一URI资源的请求中,浏览器只进行两种动作:
(1) 直接在缓存中去获取内容。如果先前有效访问的响应头包含 Expires,max-age的话,’打开新窗口’ ‘输入URI回车’ ‘前一页’ ‘后一页’这些浏览器行为不会使浏览器在Expires,max-age设置的有效期时间内去访问服务器,而是在缓存中去获取内容,但是’ 刷新’ 或 ‘重载’例外。

(2)访问服务器,根据服务器响应来获取内容。这种情况发生在设置no-cache等头标要求不缓存,或者是设置了 Expires,max-age但浏览器行为是 ‘ 刷新’ 或 ‘重载’时候。’Last-Modified’ ‘ETag’ ‘must-revalidate’ 等有些特殊,不直接受浏览器行为影响,它们也是访问服务器后,再由服务器判断是发送新的资源,还是发送一个304 Not Modfied让浏览器使用缓存中的资源。

PHP代码

function  http_cache_control( $type = ‘nocache’ , $interval =0, $mktime = ” , $etag = ” ){
if ( $type == ‘nocache’ )
{
header(‘Expires: -1′ );
header(‘Pragma: no-cache’ );
header(‘Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0′ );
}else
{
if (isset( $_SERVER [ 'HTTP_IF_NONE_MATCH' ]) &&  $etag  &&  $_SERVER [ 'HTTP_IF_NONE_MATCH' ] ==  $etag ){
header(‘HTTP/1.1 304 Not Modfied’ );
}elseif (isset( $_SERVER [ 'HTTP_IF_MODIFIED_SINCE' ]) &&  $mktime  &&  $_SERVER [ 'HTTP_IF_MODIFIED_SINCE' ] ==  gmdate ( ‘r’ , $mktime ). ‘ GMT’ ){
header(‘HTTP/1.1 304 Not Modfied’ );
}else {
if ( $mktime ){
$gmtime  =  gmdate ( ‘r’ , $mktime + $interval ). ‘ GMT’ ;
header(‘Expires: ‘ . $gmtime );
}
if ( $type == ‘public’ ){
header(‘Cache-Control: public,max-age=’ . $interval );
}elseif ( $type == ‘private’ ){
header(‘Cache-Control: private,max-age=’ . $interval . ‘,s-maxage=0′ );
}elseif ( $type == ‘none’ ){
header(‘must-revalidate,proxy-revalidate’ );
}
}
$mktime && header( ‘Last-Modified: ‘ . gmdate ( ‘r’ , $mktime ) . ‘ GMT’ );
$etag    &&  header( ‘ETag: ‘ . $etag );
}
}