设为首页收藏本站

LUPA开源社区

 找回密码
 注册
文章 帖子 博客
LUPA开源社区 首页 业界资讯 技术文摘 查看内容

Web 开发人员需知的 Web 缓存知识

2013-6-14 09:58| 发布者: 红黑魂| 查看: 2805| 评论: 0|来自: 张鑫旭

摘要: 原文出处:mnot译文出处:张鑫旭最近的译文距今已有4年之久,原文有一定的更新。今天踩着前辈们的肩膀,再次把这篇文章翻译整理下。一来让自己对web缓存的理解更深刻些,二来让大家注意力稍稍转移下,不要整天HTML5, ...

Cache-Control(缓存控制)HTTP头信息
HTTP 1.1引入了新的头信息:Cache-Control响应头信息,让网站的发布者可以更全面的控制他们的内容,更好地处理Expires的些限制。Cache-Control有用的响应头包括:

  • max-age=[秒]:表示在这个时间范围内缓存是新鲜的无需更新。类似Expires时间,不过这个时间是相对的,而不是绝对的。也就是某次请求成功后多少秒内缓存是新鲜的。
  • s-maxage=[秒]:类似max-age, 除了仅应用于共享缓存(如代理)。
  • public:标记认证的响应才能够被缓存。一般而言,需要认证HTTP请求内容会自动私有化(不会被缓存Add)。
  • privateN:允许缓存专门为某一个用户存储响应,比方说在浏览器中;共享缓存一般不会,例如在代理中。
  • no-cache:每次在释放缓存副本之前都强制发送请求给源服务器进行验证,这在确保认证有效性上很管用(和public结合使用)或者保证内容必须是即时的,不得无视缓存的所有优点,如国内的微博、twitter等的刷新显示Add
  • no-store:强制缓存在任何情况下都不要保留任何副本。
  • must-revalidate:告诉缓存,我给你准备了一些关于新鲜度的信息,在表现的时候要严格遵循之。HTTP允许缓存在某些特定情况下返回过期数据,指定了这个属性,相对于告诉缓存,你丫必须严格遵循我的规则。
  • proxy-revalidate:类似must-revalidate,除了只能应用于代理缓存。

举个板栗:

Cache-Control: max-age=3600, must-revalidate

如果Cache-ControlExpires同时存在,Cache-Control说了算N。如果你打算使用Cache-Control头,你应该好好看看”HTTP 1.1 规范“, 详见参考文章以及拓展阅读。

验证器和验证
在缓存如何工作这段译文中,我们说过,服务器以及缓存通过验证来判断内容是否改变,在不确定内容是否过期的时候,可以避免本地已经存在副本的时候下载整个内容。

验证器是很重要的,如果一个都没有,同时没有可用的新鲜度信息(ExpiresCache-Control),缓存一点儿都不会存储内容。

最常见的验证是通过Last-Modified头信息通信确定文档最后的修改时间,如果缓存有内容存储,会包含Last-Modified信息的,辅助If-Modified-Since请求,我们可以询问服务器内容是否改变了。

HTTP 1.1引入了一个新的验证器,称为Etag⑦. Etag是每次展现内容改变时候由服务器生成的唯一标识符,由于服务器控制ETag如何生成,当缓存发起If-None-Match请求的时候,如果Etag匹配,就可以确定展示内容其实是一样的。

⑦Etag: HTTP协议规格说明定义ETag为”被请求变量的实体值”。另一种说法是,ETag是一个可以与Web资源关联的记号(token)。典型的Web资源 可以一个Web页,但也可能是JSON或XML文档。服务器单独负责判断记号是什么及其含义,并在HTTP响应头中将其传送到客户端,以下是服务器端返回 的格式:ETag:”50b1c1d4f775c61:df3″客户端的查询更新格式是这样的:If-None-Match : W / “50b1c1d4f775c61:df3″如果ETag没改变,则返回状态304然后不返回,这也和Last-Modified一样。测试Etag主要 在断点下载时比较有用。

几乎所有的缓存使用Last-Modified时间作为验证器,Etag验证也开始变得流行。

所有新一代的Web服务器都对静态内容(如:文件)自动生成ETagLast-Modified头信息,而你不必做任何设置。但是,服务器对于动态内容(例如:CGI, ASP或数据库生成的网站)并不知道如何生成这些信息,参考一下编写支持缓存的脚本章节;

创建支持缓存网站的小技巧

除了使用新鲜度信息以及验证,还有其他一些技巧可以让你网站的缓存更加友好:

  • 保持URL稳定:这是缓存的金科玉律,如果你为不同页面,不同用户或不同网站提供相同的内容,他们应该使用相同的URL. 这是简单却非常行之有效的方法。例如,你的HTML中的某个引用地址是"/index.html", 则要一直使用这个地址。
  • 不同地方的图片和其他元素使用同一库
  • 对于不经常改变的图片/页面启用缓存,通过将Cache-Control: max-age头信息的值设大一点。
  • 对于定期更新的内容通过指定max-age或过期时间实现缓存。
  • 如果资源改变了(尤其下载文件),改变其名字。由于一般这种资源会有很长的过期时间,而服务器上一直是正确的版本;因此,链接这个下载资源的页面需要要比较短的过期时间(//zxx: 我司页面5分钟过期)。否则,会出现服务器的资源是新的,但页面被缓存了,其中的链接地址还是旧的,就会出现新旧版本冲突的可能Add
  • 万不得已不要变动文件:否则你要设置一个新的Last-Modified值。另外,当你更新站点的时候,只要上传改动的那些文件,而不要把整个站点都覆盖过去。
  • Cookie能不用就不用:Cookie难以被缓存,且大多情境下是没有必要的。如果你非得使用Cookie,建议用在动态页面上。
  • 减少SSL⑧的使用:因为共享缓存不能存储认证页面,只在必要的时候使用,并且在SSL页面上减少图片的使用。
  • 使用REDbot⑨检查你的网站:可以帮助你应用本文所介绍的一些概念。

⑧ SSL:全称Secure Socket Layer – 安全套接层,为Netscape所研发,用以保障在Internet上数据传输之安全,利用数据加密(Encryption)技术,可确保数据在网络上之 传输过程中不会被截取及窃听。目前一般通用之规格为40 bit之安全标准,美国则已推出128 bit之更高安全标准,但限制出境。只要3.0版本以上之I.E.或Netscape浏览器即可支持SSL。

⑨ REDbot:REDbot = RED + robot,是个机器人,检查HTTP资源,看他们如何会表现,指出常见的问题,并提出改进建议。虽然它属于HTTP一致性测试仪,但却可以找到不少HTTP相关问题。

编写支持缓存的脚本

默认情况下,大多数的脚本不会返回验证器(Last-ModifiedEtag响应头)或新鲜度信息(ExpiresCache-Control)。尽管有些脚本的确是动态的(意味着每次请求都有不同的响应),还是有很多(如搜索引擎或数据库驱动的)网站可以从缓存中受益。

一般来讲,对于同一个请求(无论是几分钟还是几天之后),如果脚本产生的内容是可重复的,则可以缓存。脚本内容的改变仅仅依赖于URL,则可以缓存。如果是依赖于Cookie,认证信息或其他外部条件,很可能不缓存。

  • 最利于缓存的脚本就是在内容改变时导出成静态文件,服务器会想对待其他Web一样对待它的,生成以及使用验证器,于是你可以好好地喝杯咖啡了。记住,只有文件更改的时候才写入,这样Last-Modified时间就会被保存下来。
  • 另外的脚本缓存之道就是使用age相关的头部,相比ExpiresCache-Control: max-age更容易些,因为是相对时间,每次新请求完成后重新设置,时间到了,再重新请求,再设置新的相对过期时间。
  • 如果上面的做法你搞不定,你还可以试试通过脚本生成一个校验器, 然后回应If-Modified-Since和/或If-None-Match请求。通过分析HTTP头信息,在适合的时候回应304 Not Modified. 不幸的是,这不是个打打酱油就能搞定的任务。

其他一些技巧

  • 不要使用POST:若是获取数据,尽量不使用POST模式,因为POST方式返回内容大部分不会被缓存,相对的,通过GET以路径和查询发送的信息被缓存存储下来供后续使用。
  • URL地址中不要嵌入特定的用户信息,除非生成的内容对于用户而言是唯一的。
  • 不要指望同一用户的所有请求来自同一主机,因为缓存经常协同工作。//zxx: 嘛意思?
  • 生成Content-Length⑩头信息。实现不难,可让你的脚本以持久连接(persistent connection)形式响应。这允许客户端在一个TCP/IP请求上请求多个内容,而不是为每次请求单独建立连接,这样你的网站相应会快很多。

详见实现注意事项。

⑩Content-Length:指明实体正文的长度,以字节方式存储的十进制数字来表示。在数据下行的过程中,Content-Length的方式要预先在服务器中缓存所有数据,然后所有数据再一股脑儿地发给客户端。

常见问题解答

缓存可用的最重要事情是?
其中一个不错的策略是找出常用的、规模较大的内容(尤其图片),然后优先处理之。

我该如何利用缓存让我的页面尽可能的快?
最应该缓存的内容设置一个较长的过期时间。验证有助于减少查看内容的时间,不过缓存仍会连接源服务器查看是不是过期了。如果缓存已经知道内容是新鲜的,直接返回。

我知道缓存是个好东西,但是我想随时知道多少人访问了我的网页!
如果你必须知道每一次页面被访问的情况,可以选择页面上的一个小元素(或页面本身),然后给这个元素一个适当的头信息使它是不可缓存。比如,你可以在每一个页面上引用一个1像素×1像素的不可缓存(如scr地址后面加个随机数Add)的透明图片。Referer头信息将会包含调用它的页面信息。

请注意,即使这样也不能给出你用户的精确统计,并且对通过互联网访问的用户也不是很友好:产生不必要的流量,并强迫用户等待未被缓存的内容从网络上下载回来。更多的信息可参见拓展阅读中的“解读访问统计”对应内容。

我该如何查看HTTP头?
许多浏览器可以查看ExpiresLast-Modified头信息,如右键→查看页面信息或类似面板。例如,在Firefox浏览器下Add

表示要看到完整的头,您可以使用Telnet⑪客户端手动连接到Web服务器上。

为此,你可能需要用一个字段指定端口(默认是80),或者连接到www.example.com:80或者www.example.com 80(注意是空格),更多设置请参考一下telnet客户端的文档。

一旦连接到该网站,输入请求。比如,你想查看http://www.example.com/foo.html的头信息,首先连接到www.example.com, 使用80端口,并输入:

GET /foo.html HTTP/1.1 [return]
Host: www.example.com [return][return]

[return]等同敲回车键,最后输入两次确认。这样就会输出头信息,然后跟着实际内容。如果只想看到头信息,使用HEAD来替换GET.

⑪Telnet:Telnet协议是TCP/IP协议族中 的一员,是Internet远程登陆服务的标准协议和主要方式。它为用户提供了在本地计算机上完成远程主机工作的能力。在终端使用者的电脑上使用 telnet程序,用它连接到服务器。终端使用者可以在telnet程序中输入命令,这些命令会在服务器上运行,就像直接在服务器的控制台上输入一样。可 以在本地就能控制服务器。要开始一个telnet会话,必须输入用户名和密码来登录服务器。Telnet是常用的远程控制Web服务器的方法。

我的页面是密码保护的,代理缓存是怎么处理的?
默认情况下,HTTP验证保护的页面是私有的,共享缓存是不能保存的。然而,你可以通过Cache-Control: public头的设置使其公有。HTTP 1.1标准兼容的缓存服务器可以使之缓存。

如果你希望这些缓存的页面在用户查看之前还要验证一下,可以组合使用Cache-Control: publicno-cache头,这相对于告诉缓存器它从缓存中送出内容前必须递交客户端的验证给原始服务器。这个头信息如下所示:

Cache-Control: public, no-cache

不管怎么,这是最小化验证最好的方法;例如,你的图片不敏感,你可以把它放在分离的目录中,并配置你的服务对它们不做强制验证。这样,那些图片就会很自然的被缓存了。

如果人们通过缓存访问我的网站,我应该担心安全吗?
SSL页面不会被代理服务器缓存,所以这个你不需要担心。但是,代理服务器就好非SSL页面请求以及URL抓取这口,你懂的,这是不安全的。无良的管理员可能就会收集网站用户的信息,尤其在URL中。

事实上,任何网络管理员都可以收集你的客户端和服务器端之间的这类信息。CGI ⑫脚本有个漏洞,会把用户名和密码放在自身的URL地址中,这很容易让其他人发现用户的登陆信息。

如果你懂得互联网安全的些基本机制,就不会对代理缓存感到任何惊讶。

⑫CGI:通用网关接口(Common Gateway Interface). 用于初始化软件服务的服务器方接口。这套接口描述了Web服务器与同一计算机上的软件的通信方式。

通用网关接口,它是一段程序,运行在服务器上,提供同客户端HTML页面的接口,通俗的讲CGI就像是一座桥,把网页和WEB服务器中的执行程序连 接起来,它把HTML接收的指令传递给服务器,再把服务器执行的结果返还给HTML页;用CGI可以实现处理表格,数据库查询,发送电子邮件等许多操作, 最常见的CGI程序就是计数器。CGI使网页变得不是静态的,而是交互式的。

我在寻找一个集成的Web发布解决方案。哪些是可缓存的?
这个是不确定的。一般来说,越复杂的系统越难缓存。最差的情况就是所有的内容都是动态生成,并且不提供校验器,与缓存压根无缘。你可以和你供应商的技术人员沟通获取更多信息,并参考下面实现注意事项。

我的图片缓存一个月后才到期,我现在就想变动!
Expires头是绕不过去的,除非缓存(浏览器或者代理)空间不足才会删除副本,缓存副本会一直使用。

最有效的方法是修改链接,这样会从源服务器获取完整的新内容。请记住,调用图片的这个页面也会被缓存的,正因如此,我们需要让图片以及其他类似的静态资源易缓存,而页面呢可以随着自身的改变(例如改变了一个图片的URL地址Add)即时更新。

如果你想摆脱特定缓存,重载内容,可以试试强制刷新(在FireFox中,shift键+reload按钮等同于处理Pragma: no-cache请求头)或者让缓存管理员使用某些接口删除内容。

我运行一个Web Hosting服务。我怎样才能让我的用户发布缓存友好的网页?
如果你使用apahe,可以考虑允许他们使用.htaccess文件并提供相应的文档。

否则你需要在每一个虚拟主机上为各种缓存属性建立预定的区域。比如:你可以指定一个叫/cache-1m的目录用来放读取后要缓存一个月的内容,然后再建一个/no-cache的目录,并在头信息中指定这么目录中的内容不被缓存。

不管上面你做的如何,总之最好优先给用户量大的客户做缓存处理。大部分服务器节约的流量以及负载都是来自高容量的网站。

我明明告诉网页要好好缓存,但它老是去请求,怎么破?
缓存服务器并不总是要求内容要保持并重用,某些条件下,他们是不保存不重用的,所有的缓存服务器都回基于文件的大小、类型(图片、页面…),或者服务器空 间的剩余来确定如何缓存。如果你的文件比较大或很热门,可能就不会被缓存。有些缓存服务器允许管理员决定哪些内容要存储,有些缓存服务器允许内容长存缓存 中,所以,它们总是可用的。


酷毙
1

雷人

鲜花

鸡蛋

漂亮

刚表态过的朋友 (1 人)

  • 快毕业了,没工作经验,
    找份工作好难啊?
    赶紧去人才芯片公司磨练吧!!

最新评论

关于LUPA|人才芯片工程|人才招聘|LUPA认证|LUPA教育|LUPA开源社区 ( 浙B2-20090187 浙公网安备 33010602006705号   

返回顶部