http报文和浏览器缓存机制
1. 请求报文
HTTP 请求由三部分组成:请求行、 请求头和请求正文
1.1请求行
请求的第一行是“方法 URL 协议/版本”,并以 回车换行作为结尾。请求行以空格分隔。格式如下:
POST /index.php HTTP/1.1
以上代码中“GET”代表请求方法,“/index.php”表示URI,“HTTP/1.1代表协议和协议的版本
1.2 请求头
一些常用的请求头信息
- Host
客户端指定自己想访问的WEB服务器的域名/IP 地址和端口号。
- Connection
客户端(浏览器)想要优先使用的连接类型,keepalive(当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,如果客户端再次访问这个服务器上的 网页,会继续使用这一条已经建立的连接)
- Accept
可接受的响应内容类型(Content-Types)。 Accept: text/plain
- Accept-Charset
可接受的字符集 Accept-Charset: utf-8
- Accept-Encoding
浏览器申明自己接收的编码方法,通常指定压缩方法,是否支持压缩,支持什么压缩方法。 Accept-Encoding: gzip, deflate
- Accept-Language:
可接受的响应内容语言列表。 Accept-Language: en-US
- User-Agent:
告诉HTTP服务器, 客户端使用的操作系统和浏览器的名称和版本.
- Cookie:
很重要的header,客户端的Cookie就是通过这个报文头属性传给服务端的!
- If-Modified-Since
把浏览器端缓存页面的最后修改时间发送到服务器去,服务器会把这个时间与服务器上实际文件的最后修改时间进行对比。如果时间一致,那么返回304,客户端就直接使用本地缓存文件。如果时间不一致,就会返回200和新的文件内容。客户端接到之后,会丢弃旧文件,把新文件缓存起来,并显示在浏览器中。
例如:If-Modified-Since: Thu, 09 Feb 2012 09:07:57 GMT。
- If-None-Match
If-None-Match和ETag一起工作,工作原理是在HTTP Response中添加ETag信息。 当用户再次请求该资源时,将在HTTP Request 中加入If-None-Match信息(ETag的值)。如果服务器验证资源的ETag没有改变(该资源没有更新),将返回一个304状态告诉客户端使用本地缓存文件。否则将返回200状态和新的资源和Etag. 使用这样的机制将提高网站的性能
例如: If-None-Match: “03f2b33c0bfcc1:0”
- Pragma
防止页面被缓存, 在HTTP/1.1版本中,它和Cache-Control:no-cache作用一模一样
Pargma只有一个用法, 例如: Pragma: no-cache
注意: 在HTTP/1.0版本中,只实现了Pragema:no-cache, 没有实现Cache-Control
- Cache-Control
这个是非常重要的规则。 这个用来指定Response-Request遵循的缓存机制。如以下设置,相当于让服务端将对应请求返回的响应内容不要在客户端缓存:Cache-Control: no-cache
- Content-Length
以8进制表示的请求体的长度 Content-Length: 348
- Content-Type
请求体的MIME类型 (用于POST和PUT请求中) Content-Type: application/x-www-form-urlencoded
- Referer
表示浏览器所访问的前一个页面,可以认为是之前访问页面的链接将浏览器带到了当前页面。Referer其实是Referrer这个单词,但RFC制作标准时给拼错了,后来也就将错就错使用Referer了。 Referer: http://itbilu.com/nodejs
- Upgrade
要求服务器升级到一个高版本协议。 Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11
- Via
告诉服务器,这个请求是由哪些代理发出的。 Via: 1.0 fred, 1.1 itbilu.com.com (Apache/1.1)
2. 响应报文
HTTP 响应也是由三个部分组成,分别是:状态行、消息报头和响应正文
2.1 状态行
状态行由协议版本、数字形式的状态代码,及相应的状态描述组成,各元素之间以空格分隔,结尾时回车换行符,格式如下:
HTTP-Version Status-Code Reason-Phrase CRLF
HTTP-Version 表示服务器 HTTP 协议的版本,Status-Code 表示服务器发回的响应代码,Reason-Phrase 表示状态代码的文本描述,CRLF 表示回车换行。例如:
HTTP/1.1 200 OK (CRLF)
1> 响应状态码
1xx 消息,一般是告诉客户端,请求已经收到了,正在处理,别急...。
2xx 处理成功,一般表示:请求收悉、我明白你要的、请求已受理、已经处理完成等信息。
3xx 重定向到其它地方。它让客户端再发起一个请求以完成整个处理。
4xx 处理发生错误,责任在客户端,如客户端的请求一个不存在的资源,客户端未被授权,禁止访问等。
5xx 处理发生错误,责任在服务端,如服务端抛出异常,路由出错,HTTP版本不支持等。
2> 常见的响应状态码
200 OK 处理成功!
301 永久重定向 Location响应首部的值仍为当前URL,因此为隐藏重定向;
302 临时重定向 显式重定向, Location响应首部的值为新的URL。
303 See Other redirect到其它的页面,目标的URL通过响应报文头的Location告诉你。
304 Not Modified 告诉客户端,你请求的这个资源至你上次取得后,并没有更改,你直接用你本地的缓存
400 Bad Request 客户端请求有语法错误,不能被服务器所理解。
401 Unauthorized 请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用。
403 Forbidden 服务器收到请求,但是拒绝提供服务。
404 Not Found 你最不希望看到的,即找不到页面。
500 Internal Server Error 看到这个错误,你就应该查查服务端的日志了,肯定抛出了一堆异常。
503 Server Unavailable 服务器当前不能处理客户端的请求,一段时间后可能恢复正常。
2.2 响应头
常见的响应头
- Access-Control-Allow-Origin
指定哪些网站可以跨域源资源共享 Access-Control-Allow-Origin: *
- Allow
对于特定资源的有效动作; Allow: GET, HEAD 固定
- Cache-Control
通知从服务器到客户端内的所有缓存机制,表示它们是否可以缓存这个对象及缓存有效时间。其单位为秒 Cache-Control: max-age=3600 固定
- Connection
针对该连接所预期的选项 Connection: close 固定
- Content-Encoding
响应资源所使用的编码类型。 Content-Encoding: gzip
- Content-Language
响就内容所使用的语言 Content-Language: zh-cn
- Content-Length
响应消息体的长度,用8进制字节表示 Content-Length: 348
- Content-Location
所返回的数据的一个候选位置 Content-Location: /index.htm
- Content-Type
当前内容的MIME类型 Content-Type: text/html; charset=utf-8
- Date
此条消息被发送时的日期和时间(以RFC 7231中定义的"HTTP日期"格式来表示) Date: Tue, 15 Nov 1994 08:12:31 GMT
- ETag
对于某个资源的某个特定版本的一个标识符,通常是一个 消息散列 ETag: "737060cd8c284d8af7ad3082f209582d"
- Expires
指定一个日期/时间,超过该时间则认为此回应已经过期 Expires: Thu, 01 Dec 1994 16:00:00 GMT
- Last-Modified
所请求的对象的最后修改日期(按照 RFC 7231 中定义的“超文本传输协议日期”格式来表示) Last-Modified: Dec, 26 Dec 2015 17:30:00 GMT
- Location
用于在进行重定向,或在创建了某个新资源时使用。 Location: http://www.itbilu.com/nodejs
- Pragma
与具体的实现相关,这些响应头可能在请求/回应链中的不同时候产生不同的效果 Pragma: no-cache
- Server
服务器的名称 Server: nginx/1.6.3
- Set-Cookie
设置HTTP cookie Set-Cookie: UserID=itbilu; Max-Age=3600; Version=1
- Status
通用网关接口的响应头字段,用来说明当前HTTP连接的响应状态。 Status: 200 OK
- Transfer-Encoding
用表示实体传输给用户的编码形式。包括:chunked、compress、 deflate、gzip、identity。 Transfer-Encoding: chunked
- Upgrade
要求客户端升级到另一个高版本协议。 Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11
- Vary
告知下游的代理服务器,应当如何对以后的请求协议头进行匹配,以决定是否可使用已缓存的响应内容而不是重新从原服务器请求新的内容。 Vary: *
- Via
告知代理服务器的客户端,当前响应是通过什么途径发送的。 Via: 1.0 fred, 1.1 itbilu.com (nginx/1.6.3)
3. 浏览器缓存
3.1 缓存的优点:
1> 服务器响应更快:因为请求从缓存服务器(离客户端更近)而不是源服务器被相应,这个过程耗时更少,让服务器看上去响应更快。
2> 减少网络带宽消耗:当副本被重用时会减低客户端的带宽消耗;客户可以节省带宽费用,控制带宽的需求的增长并更易于管理。
3.2 缓存工作原理
3.2.1 首先了解下缓存的相关字段
通用首部: 请求报文和响应报文双方都会使用的首部
字段名 | 说明 |
---|---|
Cache-Control | 控制缓存的行为 |
Pragma | http1.0产物,值为no-cache时禁用缓存 |
请求首部
字段名 | 说明 |
---|---|
if-Match | 比较ETag(资源计算得出一个唯一标志符,比如md5标志)是否一致 |
if-None-Match | 比较ETag(资源计算得出一个唯一标志符,比如md5标志)是否【不一致】 |
if-Modified-Since | 比较资源最后更新时间(Last-Modified的值)是否一致 |
if-Modified-Since | 比较资源最后更新时间(Last-Modified的值)是否【不一致】 |
响应首部
字段名 | 说明 |
---|---|
ETag | 资源的匹配信息,例如Etag: "5d8c72a5edda8d6a:3239" |
实体首部:包含在请求报文和响应报文中的实体部分所使用的首部。
字段名 | 说明 |
---|---|
Expires | http1.0产物,实体主体过期时间 |
Last-Modified | 资源最后修改时间 |
3.2.2 http1.0时代缓存方式
在 http1.0 时代,给客户端设定缓存方式可通过两个字段——Pragma和Expires来规范。虽然这两个字段早可抛弃,但为了做http协议的向下兼容,你还是可以看到很多网站依旧会带上这两个字段。
1、Pragma
实现禁用缓存,当该字段值为no-cache的时候(事实上现在RFC中也仅标明该可选值),会知会客户端不要对该资源读缓存,即每次都得向服务器发一次请求才行。
Pragma的优先级是高于Cache-Control的。
Pragma -> Cache-Control
2、Expires
实现启用缓存和定义缓存时间, Expires的值对应一个GMT(格林尼治时间),比如Mon, 22 Jul 2002 11:12:01 GMT来告诉浏览器资源缓存过期时间,如果还没过该时间点则不发请求。
如果Pragma头部和Expires头部同时存在,则起作用的会是Pragma
3.2.3 http1.1时代缓存方式
针对上述的“Expires时间是相对服务器而言,无法保证和客户端时间统一”的问题,http1.1新增了 Cache-Control 来定义缓存过期时间。
注意:若报文中同时出现了 Expires 和 Cache-Control,则以 Cache-Control 为准。
也就是说优先级从高到低分别是
Pragma -> Cache-Control -> Expires
Cache-Control也是一个通用首部字段,这意味着它能分别在请求报文和响应报文中使用。在RFC中规范了 Cache-Control 的格式为:
"Cache-Control" ":" cache-directive
作为请求首部时,cache-directive 的可选值有:
作为响应首部时,cache-directive 的可选值有:
这里要注意下:
- no-cahce并不是表示无缓存,而是指使用缓存一定要先验证新鲜度
- response header的
no-cache
和max-age=0
和request header的max-age=0
的作用是一样的:都要求在使用缓存之前验证新鲜度
Cache-Control 允许自由组合可选值,例如:
Cache-Control: max-age=3600, must-revalidate
它意味着该资源是从原服务器上取得的,且其缓存(新鲜度)的有效时间为一小时,在后续一小时内,用户重新访问该资源则无须发送请求。 当然这种组合的方式也会有些限制,比如 no-cache 就不能和 max-age、min-fresh、max-stale 一起搭配使用。
3.2.3 http1.1时代的补充
如果客户端向服务器发了请求,那么是否意味着一定要读取回该资源的整个实体内容呢?如果客户端现在存有的缓存文件,其实跟自己所有的文件是一致的,其实是可以复用的。为了让客户端与服务器之间能实现缓存文件是否更新的验证、提升缓存的复用率,Http1.1新增了几个首部字段来做这件事情。
首先,了解下etag 和 last-modified这两个关键点,他们有如下的对应关系。
etag —— if-none-match
etag —— If-Match
last-modified —— if-modified-since
last-modified —— If-Unmodified-Since
1、Last-Modified
服务器将资源传递给客户端时,会将资源最后更改的时间以“Last-Modified: GMT”的形式加在实体首部上一起返回给客户端。
Last-Modified: Fri, 22 Jul 2016 01:47:00 GMT
客户端会为资源标记上该信息,下次再次请求时,会把该信息附带在请求报文中一并带给服务器去做检查,若传递的时间值与服务器上该资源最终修改时间是一致的,则说明该资源没有被修改过,直接返回304状态码,内容为空,这样就节省了传输数据量 。如果两个时间不一致,则服务器会发回该资源并返回200状态码,和第一次请求时类似。这样保证不向客户端重复发出资源,也保证当服务器有变化时,客户端能够得到最新的资源。一个304响应比一个静态资源通常小得多,这样就节省了网络带宽。
至于传递标记起来的最终修改时间的请求报文首部字段一共有两个:
If-Modified-Since: Last-Modified-value
该请求首部告诉服务器如果客户端传来的最后修改时间与服务器上的一致,则直接回送304 和响应报头即可。
当前各浏览器均是使用的该请求首部来向服务器传递保存的 Last-Modified 值。
If-Unmodified-Since: Last-Modified-value
该值告诉服务器,若Last-Modified没有匹配上(资源在服务端的最后更新时间改变了),则应当返回412(Precondition Failed) 状态码给客户端。
Last-Modified 存在一定问题,如果在服务器上,一个资源被修改了,但其实际内容根本没发生改变,会因为Last-Modified时间匹配不上而返回了整个实体给客户端(即使客户端缓存里有个一模一样的资源)。这个问题可以ETag来解决
2、ETag
为了解决上述Last-Modified可能存在的不准确的问题,Http1.1还推出了 ETag 实体首部字段。 服务器会通过某种算法,给资源计算得出一个唯一标志符(比如md5标志),在把资源响应给客户端的时候,会在实体首部加上“ETag: 唯一标识符”一起返回给客户端。例如:
Etag: "5d8c72a5edda8d6a:3239"
客户端会保留该 ETag 字段,并在下一次请求时将其一并带过去给服务器。服务器只需要比较客户端传来的ETag跟自己服务器上该资源的ETag是否一致,就能很好地判断资源相对客户端而言是否被修改过了。
如果服务器发现ETag匹配不上,那么直接以常规GET 200回包形式将新的资源(当然也包括了新的ETag)发给客户端;如果ETag是一致的,则直接返回304知会客户端直接使用本地缓存即可。
那么客户端是如何把标记在资源上的 ETag 传回给服务器的呢?请求报文中有两个首部字段可以带上 ETag 值:
If-None-Match: ETag-value
告诉服务端如果 ETag 没匹配上需要重发资源数据,否则直接回送304 和响应报头即可。 当前各浏览器均是使用的该请求首部来向服务器传递保存的 ETag 值。
If-Match: ETag-value
告诉服务器如果没有匹配到ETag,或者收到了“*”值而当前并没有该资源实体,则应当返回412(Precondition Failed) 状态码给客户端。否则服务器直接忽略该字段。
3.3 火狐浏览器缓存分析实例
3.3.1 第一次访问
请求头中没有关于缓存的字段,响应200,并且响应头中则返回了ETag字段。
ETag W/"651c64-iihm0BriQfynDiDtEbdScsPqrwA"
3.3.2 地址栏直接回车
请求头中带上了关于缓存的字段(If-None-Match),并且带上了第一次Etag返回的值
If-None-Match W/"651c64-iihm0BriQfynDiDtEbdScsPqrwA"
响应 304,并且继续返回Etag字段
3.3.3 按f5
请求头中带上了关于缓存的字段(If-None-Match,Cache-Control),并且带上了第一次Etag返回的值
Cache-Control max-age=0
If-None-Match W/"651c64-iihm0BriQfynDiDtEbdScsPqrwA"
响应 304,并且继续返回Etag字段
和直接在地址栏回车的区别是加了Cache-Control max-age=0
头部,意思是告诉浏览器要进行新鲜度的检查,我们发现检查后发现时最新资源,所有返回了304
。
3.3.4 ctrl + f5
请求头中带上了关于缓存的字段(Cache-Control,Pragma)
Cache-Control no-cache
Pragma no-cache
响应 200,并且返回Etag字段
这个操作的意思是我不光要最新资源,并且中间的各级缓存(不只是浏览器缓存,可能还有中间的prxoy缓存等)都不要返给我。
3.3.5 总结:
浏览器的刷新访问行为是有自己的一套准则的,以上是我试验的火狐浏览器,大家可以测试下自己的浏览器,其实我们可以认识到不同的操作,会有不同的请求策略,一些静态资源浏览器可能会为其增加新的请求头部信息,以此来达到缓存的策略。
参考资料:
https://www.jianshu.com/p/b1ea16450fff
https://cnbin.github.io/blog/2016/02/20/http-qing-qiu-,-xiang-ying-,-huan-cun/
https://github.com/rccoder/blog/issues/12
http://imweb.io/topic/5795dcb6fb312541492eda8c
http报文和浏览器缓存机制的更多相关文章
- Java缓存学习之二:浏览器缓存机制
浏览器端的九种缓存机制介绍 浏览器缓存是浏览器端保存数据用于快速读取或避免重复资源请求的优化机制,有效的缓存使用可以避免重复的网络请求和浏览器快速地读取本地数据,整体上加速网页展示给用户.浏览器端缓存 ...
- 详解浏览器缓存机制与Apache设置缓存
一.详解浏览器缓存机制 对于,如何说明缓存机制,在网络上找到了两张图,个人认为思路是比较清晰的.总结时,上图. 这里需要注意的有两点: 1.Last-Modified.Etag是响应头里的数据 2.I ...
- atitit。浏览器缓存机制 and 微信浏览器防止缓存的设计 attilax 总结
atitit.浏览器缓存机制 and 微信浏览器防止缓存的设计 attilax 总结 1. 缓存的一些机制 1 1.1. http 304 1 1.2. 浏览器刷新的处理机制 1 1.3. Expir ...
- 浏览器缓存机制<转>
转这篇文章是感觉可以在图片加载的时候,也使用这样的缓存策略 作者:吴秦出处:http://www.cnblogs.com/skynet/本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或 ...
- WEB请求过程(http解析,浏览器缓存机制,域名解析,cdn分发)
概述 发起一个http请求的过程就是建立一个socket通信的过程. 我们可以模仿浏览器发起http请求,譬如用httpclient工具包,curl命令等方式. curl "http://w ...
- HTTP浏览器缓存机制
来自:http://kb.cnblogs.com/page/165307/ 浏览器缓存机制 浏览器缓存机制,其实主要就是HTTP协议定义的缓存机制(如: Expires: Cache-control等 ...
- HTTP 协议 -- 浏览器缓存机制
浏览器缓存机制 浏览器缓存机制主要是 HTTP 协议定义的缓存机制. HTTP 协议中有关缓存的缓存信息头的关键字有 Cache-Control,Pragma,Expires,Last-Modifie ...
- 浏览器缓存机制(HTTP缓存机制)
其机制是根据HTTP报文的缓存标识进行的. 过程:浏览器发起HTTP请求 – 服务器响应该请求.那么浏览器第一次向服务器发起该请求后拿到请求结果,会根据响应报文中HTTP头的缓存标识,决定是否缓存结果 ...
- <转>浏览器缓存机制
本篇博客转载自github,原文地址:浏览器缓存篇 前言 在前端开发中,缓存有利于加快网页的加载速度,同时缓存能够被反复利用,所以可以减少流量和带宽的开销. 缓存的分类有很多种,CDN缓存.数据库缓存 ...
随机推荐
- L1 loss L2 loss
https://www.letslearnai.com/2018/03/10/what-are-l1-and-l2-loss-functions.html http://rishy.github.io ...
- 第二章:RESTful API
学习内容 使用Spring MVC编写Restful API 使用Spring MVC处理其他web应用常见的需求和场景 如何处理静态资源和异常,如何使用Spring MVC的拦截器,文件的上传下载, ...
- spring入门(一) 根据xml实例化一个对象
文档: https://docs.spring.io/spring/docs/5.0.9.RELEASE/spring-framework-reference/core.html#beans-fact ...
- 使用缓存时出现java.io.NotSerializableException:xxx.xxx.xxx.Bean解决办法
解决方案: 开发过程中如果想缓存某个JavaBean,请确保它所引用的对象都implents Serializable,如果某个对象不需要被cache,可以加上transient关键字,否则Ehc ...
- 关于truthy 和 falsy
一,强制类型转换 JavaScript 在需要用到布尔类型值的上下文中使用强制类型转换(Type Conversion )将值转换为布尔值,比如:在条件语句或者循环语句中 一,truthy 在java ...
- 替换html里面的\r\n及解决记事本中的每个段落只有一行的情形
1. 在用python爬取小说的时候, 发现在内容里每次换行都有\r\n(即回车, 换行)出现. 此时可以采用 s.replace('\\r\\n','') , 其中s为字符串类型. 2. 在爬取完 ...
- deepin系统无线网络卡死或者极慢的解决方案
在初次安装deb或者fedara系列的桌面发行版的之后,经常会出现无线网络极慢甚至卡死的状况. 笔者在初次使用deepin系统的时候,也遇到同样的问题,很大程度上是由于没有安装对应的驱动. 下面给出对 ...
- 启用image-filter扩展模块
进入lnmp目录打开lnmp.conf配置文件 修改Nginx_Modules_Options=' --prefix=/usr/local/nginx --with-http_image_filter ...
- [NodeJs系列][译]理解NodeJs中的Event Loop、Timers以及process.nextTick()
译者注: 为什么要翻译?其实在翻译这篇文章前,笔者有Google了一下中文翻译,看的不是很明白,所以才有自己翻译的打算,当然能力有限,文中或有错漏,欢迎指正. 文末会有几个小问题,大家不妨一起思考一下 ...
- Apache Maven(六):存储库
Maven 存储库主要是存放一些第三方依赖jar包等. 严格来说,只有两种存储库:本地和远程,本地存储库是指您远程下载到本地的一个缓存,还包含尚未发布的临时构建文件.远程存储库是指一些可以通过各种协议 ...