53.HTTP缓存详解
来源:互联网 发布:linux统计文件行数 编辑:程序博客网 时间:2024/06/02 19:41
- 简介
- 浏览器缓存机制
- HTML meta标签
- HTTP 头部信息
- expires字段
- 通过cache-control字段控制缓存策略
- EtagIf-None-Match
- Last-ModifiedIf-Modified-Since
- ETag与Last-Modified
- 缓存与浏览器刷新的关系
转载请注明原始链接:http://blog.csdn.net/a464057216/article/details/52780055。本篇博客用Mac OS X Sierra上的Firefox 47.0.1版本做的实验,对于其他浏览器或版本可能会有不同。
简介
缓存主要分为两类:服务端缓存、客户端缓存。
服务端缓存包括转发代理服务器缓存、反向代理服务器缓存、CDN缓存等。
客户端缓存一般指浏览器缓存,比如Chrome浏览器查看缓存可以访问chrome://cache
。
浏览器缓存机制
主要分为两种:通过HTML <meta>
标签和通过HTTP报文头。
HTML meta标签
<meta http-equiv="pragma" content="no-cache" />
用来告诉浏览器每次想要使用缓存前都需要到服务器验证缓存是否有更新。并不是所有浏览器都支持这个功能,缓存服务器也不会解析HTML文件的内容,所以一般不要使用这种方式。
HTTP 头部信息
expires字段
HTTP 1.0中,服务器通过回应给客户端的HTTP Response的头部的expires
字段说明资源的过期时间,使用该字段容易受到服务器与客户端时区及时间差异的影响。比如在服务端使用Flask将响应的缓存有效期设置为当前时间的18小时以后:
# Written by - CSDN: Mars Loo的博客GMT_FORMAT = '%a, %d %b %Y %H:%M:%S GMT'@app.route('/', methods=["GET",])def index(): r = make_response(render_template('index.html')) exp = datetime.datetime.utcnow() + datetime.timedelta(hours=18) r.headers['Expires'] = exp.strftime(GMT_FORMAT) return r.make_conditional(request)
在Mac OS X Sierra上使用Firefox 47.0.1访问该地址:
在服务端修改index.html
文件的内容,然后在浏览器地址栏重新输入地址后访问,发现并没有加载最新的服务器端内容(状态码200前面灰色的圆圈表示加载的是浏览器缓存):
通过cache-control字段控制缓存策略
HTTP 1.1标准中设计了cache-control
字段用于替代expires
字段(如果两者同时存在,以cache-control
的设置为准),cache-control
可以实现比expires
更精细的缓存控制比如:
- max-age:缓存的过期时间(以秒为单位)。
- public:响应可以被任何缓存区域缓存,比如客户端浏览器、代理服务器等。
- private:响应的部分或全部内容属于一个单独的用户,只允许客户端浏览器缓存,不允许代理服务器缓存。
- no-cache:无论如何,客户端浏览器必须先与服务器重验证缓存中的响应是否被更改,然后才能使用该响应来满足后续对同一个网址的请求。
如果之前的响应包含ETag
字段,可能会使用If-Match
字段或If-None-Match
字段验证;如果之前的响应包含Last-Modified
字段,可能会使用If-Modified-Since
字段或If-Unmodified-Since
字段验证。比如服务端设置了no-cache
、30秒的max-age
和ETag
字段:
# Written by - CSDN: Mars Loo的博客@app.route('/', methods=["GET",])def index(): r = make_response(render_template('index.html')) r.add_etag() r.cache_control.max_age = 30 r.cache_control.no_cache = True return r.make_conditional(request)
使用FF访问该页面:
30秒之内在地址栏中输入地址敲回车后,浏览器向服务器发送请求重验证,如果资源没有发生过修改,返回304 Not Modified,浏览器从缓存加载页面:
- must-revalidate:如果资源过期,客户端浏览器必须先与服务器确认缓存中的响应是否被更改,然后才能使用该响应来满足后续对同一个网址的请求(各个浏览器本身的实现也应该如此,只是
must-revalidate
将这一过程具体化了)。验证方法同上。比如服务端设置了Last-Modified
、max-age
和must-revalidate
属性:
# Written by - CSDN: Mars Loo的博客GMT_FORMAT = '%a, %d %b %Y %H:%M:%S GMT'@app.route('/', methods=["GET",])def index(): r = make_response(render_template('index.html')) r.last_modified = datetime.datetime.utcnow() r.cache_control.max_age = 30 r.cache_control.must_revalidate = True return r.make_conditional(request)
FF浏览器第一次访问:
30秒之内在地址栏中输入地址敲回车后,浏览器会读取缓存:
30秒之后在地址栏中输入地址敲回车后,浏览器会去服务端验证缓存是否过期。从上面服务端的代码看,意味着下次认证会返回资源已经发生了修改,响应如下:
将服务端资源改成Last-Modified
没有发生更改的情形:
# Written by - CSDN: Mars Loo的博客GMT_FORMAT = '%a, %d %b %Y %H:%M:%S GMT'lm = datetime.datetime.utcnow()@app.route('/', methods=["GET",])def index(): r = make_response(render_template('index.html')) r.last_modified = lm r.cache_control.max_age = 30 r.cache_control.must_revalidate = True return r.make_conditional(request)
在30秒缓存过期后请求同样的地址,响应为304 Not Modified
,客户端浏览器加载缓存:
- no-store:禁止任何缓存区域缓存响应。
比如服务端设置了no-store
:
# Written by - CSDN: Mars Loo的博客@app.route('/', methods=["GET",])def index(): r = make_response(render_template('index.html')) r.add_etag() r.cache_control.no_store = True return r.make_conditional(request)
使用FF浏览器访问该页面:
第二次在地址栏中输入地址敲回车后,浏览器还是会向服务器发送请求:
Etag/If-None-Match
ETag
可以理解为资源的摘要签名信息,如果资源未发生改变,该签名信息是不会改变的。客户端第一次请求服务端的某静态文件时,服务端可以在ETag
字段回应资源的签名信息。接下来的请求中,如果客户端判断缓存已经过期(超过了max-age
),会在If-None-Match
字段填充缓存的ETag
信息询问服务端资源是否发生过变动,如果发生过变化,服务端回应200的正常响应,如果未发生过变化,返回304 Not Modified响应,浏览器加载缓存,304响应不包含Response的body部分,提高了传输效率。
Last-Modified/If-Modified-Since
Last-Modified
是客户端第一次请求服务端的某静态文件时,服务端填充的资源最后修改时间。接下来的请求中,如果客户端判断缓存已经过期(超过了max-age
),会在If-Modified-Since
字段填充缓存的Last-Modified
信息询问服务端资源是否发生过变动,如果发生过变化,服务端回应200的正常响应,如果未发生过变化,返回304 Not Modified响应。
ETag与Last-Modified
使用Last-Modified
字段可能有如下缺点:资源内容未发生变化,但是最后修改时间变了,造成带宽浪费;只能精确到秒级,如果资源在1秒内被多次修改,不能准确体现资源变化,造成客户端获取的数据不准确。ETag
可以精确表示资源是否发生变化,当两个字段同时存在时,以ETag
为准。
缓存与浏览器刷新的关系
比如Mac上FF浏览器有Command
+r
普通刷新和Shift
+Command
+r
强制刷新。普通刷新相当于浏览器在发往Server端的请求头中添加字段Cache-Control:max-age=0
,表示从客户端到服务端的沿途服务器都需要重新校验缓存:
强制刷新相当于浏览器在发往服务器的请求头中添加Pragama: no-cache
和Cache-Control: no-cache
头,表示客户端到服务端的节点无需重新验证缓存是否过期而是强制要求服务端返回一个非缓存的版本(即使资源未发生变化,也不返回304 Not Modified
,而是返回200的正常响应):
如果觉得我的文章对您有帮助,欢迎关注我(CSDN:Mars Loo的博客)或者为这篇文章点赞,谢谢!
如下几篇文章是我在学习HTTP协议时总结的博文,欢迎参考:
1. HTTP代理及重定向
2. HTTP认证(基本认证与摘要认证)
3. HTTP、HTTPS基本原理
- 53.HTTP缓存详解
- Yii2详解HTTP缓存
- HTTP缓存详解
- 关于http缓存详解
- HTTP 缓存机制详解
- HTTP缓存详解
- HTTP缓存机制详解
- HTTP缓存机制详解
- HTTP详解-请求、响应、缓存
- HTTP详解(2)-请求、响应、缓存
- HTTP详解(2)-请求、响应、缓存
- 写给前端的http缓存详解
- HTTP详解(2)-请求、响应、缓存
- HTTP详解(2)-请求、响应、缓存
- 浏览器 HTTP 协议缓存机制详解
- HTTP详解(2)-请求、响应、缓存
- HTTP详解(2)-请求、响应、缓存
- HTTP详解(2)-请求、响应、缓存
- 做好这4个细节设计,让你的移动APP 用户体验脱颖而出
- LuManager
- java设计模式(六)--观察者模式
- 【知识库专访】亲加CTO郝飞:直播技术架构解密与优化之道
- 转载:java程序员如何拿到2万月薪
- 53.HTTP缓存详解
- 手机端web学习基础--from慕课网
- 在C#中利用句柄发送消息
- java并发编程读书笔记(1)-- 对象的共享
- 技术栈
- java并发编程实践学习(2)--对象的组合
- IDA调试so文件基础篇
- java并发编程:并发容器之CopyOnWriteArrayList(转)
- java并发编程(2)--volatile(转)