八一八浏览器缓存
10/Sep 2014
今天由于需求变更,修改了部分前端代码,测试没问题之后进行了部署。交付测试时,发现修改的代码不起作用。而且比较奇怪的是一般手机浏览器没有问题,但微信内嵌浏览器内的结果还停留在部署之前的状态。分析后得知应该是缓存机制引起的。这里总结一下关于浏览器缓存的知识。
1. 为什么需要浏览器缓存
网络的带宽总是有限的,尤其是在并发比较高的情况下,能节约一点儿是一点儿。对于大多数网站来说,类似js, css,图片等静态文件是很少变化的。我们便可以在用户的一次请求之后在本地缓存静态文件。用户进行同样的请求(url一致)时,相应文件直接在本地读取,快速获得响应。 除了减少服务器压力和带宽外,缓存机制还可以极大提高页面的显示速度。
2. 缓存协商
缓存的文件是由服务器生成,在本地保存, 但不是保存下来就万事大吉, 合理使用缓存需要双方动态沟通,这样就引入了缓存协商。下面是具体的请求过程分析:
(1) 当浏览器第一次请求某个URL时,顺利访问的话,服务器返回状态200的状态, ; 同时会返回给浏览器一些Headers集合,
如果只设定了Last-Modified和Etag头信息,那么浏览器接收到服务器这些信息后,就会将资源缓存在本地目录中,同时
保存文件的上述信息.
(2) 再次请求时,根据 HTTP 协议的规定,浏览器会向服务器传送 If-Modified-Since 与 If-None-Match 报头,这
两个报头实际上是第一次请求时服务器返回的Last-Modified,Etag。发送这两个报头目地是询问服务器,该资源在
时间内有没有被修改过。如 果该资源未被修改,则服务器会直接返回HTTP 304 (Not Changed.)状态码,内容为
空,此时不会下载资源,浏览器则自动从缓存目录中读取资源。
(3) 只使用Last-Modified和Etag 可以减少传输成本,但不会减少http请求数量。如果给文件加上关于过期时间(Expires)
的header报文,这样浏览器就会先检查缓存中的文件,如果没有过期,就直接使用缓存中的文件,从而不会 发送http请求。
3. 缓存存在的问题
既然存在了本地,那么最大的问题就是一旦服务器的文件更新了,而浏览器还在使用本地的缓存,
会造成服务器端的修改不能生效。 我们碰到的问题刚好可以对号入座。
4. 解决之道
4.1 设置html的缓存相关信息
在html的头部加入如下信息:
<META HTTP-EQUIV="pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">
<META HTTP-EQUIV="expires" CONTENT="0">
如果是动态语言生成的页面可以类似设置:
<%
// 将过期日期设置为一个过去时间
response.setHeader("Expires", "Sat, 6 May 1995 12:00:00 GMT");
// 设置 HTTP/1.1 no-cache 头
response.setHeader("Cache-Control", "no-store,no-cache,must-revalidate");
// 设置 IE 扩展 HTTP/1.1 no-cache headers, 用户自己添加
response.addHeader("Cache-Control", "post-check=0, pre-check=0");
// 设置标准 HTTP/1.0 no-cache header.
response.setHeader("Pragma", "no-cache");
%>
4.2 使用POST代替GET
根据 HTTP 规范,GET 用于信息获取,是幂等操作。也就是说,当使用相同的URL重复GET请求会返回预期的相同结果时,GET方法才是适用的。当对一个请求有副作用的时候(例如,提交数据注册新用户时),应该使用POST请求而不是GET。 所以浏览器会对GET请求做缓存处理。 不会对POST做缓存。
4.3 在url后加随机参数
在一次请求的URL后加随机数,服务器就会认为是不同的请求,就会传回最新的文件覆盖旧的文件。但这种方法仅限于动态语言。
<%@ page import="java.util.Random"%>
<html>
<head>
<script src="js/fuck.js?<%=new Random().nextInt(1000);%>"></script>
</head>
...
</html>
4.4 给修改后的文件换个名字
上面的三种方法都是完全舍弃缓存优点的做法,如果既想使修改生效,又想继续使用缓存机制应该怎么办呢? 其实最简单的做法就是将修改过的文件换个名称,比如加个时间戳之类的东西。这是的文件就变成了新鲜出炉的文件,本地压根儿就没有,只得乖乖从服务器端获取。
这种方法理论上是行的通的,有时间我会试试,可惜我没有时间了。 你有时间不妨一试?
参考:
浅谈浏览器缓存
浏览器缓存url请求
浏览器缓存
百科