HTTP
2020-04-16 11:08:25 0 举报
AI智能生成
前端HTTP知识梳理
作者其他创作
大纲/内容
演变
HTTP 2
由来
这些年来,<b>网页变得越来越复杂,更多的数据通过 HTTP 请求被传输</b>。<br>HTTP/1.1链接需要请求以正确的顺序发送,理论上可以用一些并行的链接(一般是5到8个),导致成本和复杂性显著加大。<br>比如,HTTP流水线就成为了Web开发的负担。<br><br>在2010年到2015年,谷歌通过实现一个实验性的SPDY协议,展示了另一种在客户端和服务器端交换数据的方式。<br>其收集了浏览器和服务器端的开发者的焦点问题。明确了 增加响应数量和解决传输数据复用 的目标,SPDY成为了HTTP/2协议的基础。<br>
与 HTTP/1.1 的不同
1. HTTP/2是<b><font color="#0076b3">二进制协议</font></b>而<b>不是文本协议</b>。<font color="#924517"><b>不再可读</b>,<b>也不可无障碍的手动创建</b>。</font><br>尽管有此障碍,改善的优化技术现在可被实施。<br>2. 这是一个复用协议。<b><font color="#0076b3">并行的请求能在同一个链接中处理</font></b>,移除了HTTP/1.x中顺序和阻塞的约束。<br>3.<font color="#0076b3"> <b>压缩 headers。因为 headers 在一系列请求中常常是相似的</b></font>,这移除了传输数据的重复性,降低了传输数据的成本。<br>4. <b>允许服务器 通过 <font color="#0076b3">server push</font> 的机制 在被请求前 <font color="#0076b3">向客户端缓存传输数据</font></b>。<br>
高流量的站点最迅速地接受了 HTTP2,在数据传输上节省了可观的成本和支出。<br><br>这种迅速的普及率很可能是因为 HTTP2 不需要站点和应用做出改变:使用HTTP/1.1和HTTP/2对他们来说是透明的。<br>拥有一个最新的服务器和新点的浏览器进行交互就足够了。<br>只有一小部分群体需要做出改变,而且随着陈旧的浏览器和服务器的更新,不需Web开发者做什么,用的人自然就增加了。<br>
继续优化
建立在 TCP(传输控制协议/Transmission Control Protocol 是一种面向连接的、可靠的、基于字节流的<b>传输层</b>通信协议)<br> 之上的 HTTP2.0 仍然受到 TCP 一些特性的制约。<br>谷歌开发的 QUIC <b>基于 UDP 协议</b>,2018年10月被确立为 <b>HTTP3.0 </b>的基础
HTTP 消息
HTTP/1.x 报文<br>请求和响应结构<br>
<ol><li>一行起始行用于描述要执行的请求,或者是对应的状态,成功或失败。这个起始行总是单行的。<br></li><li>一个可选的HTTP头集合指明请求或描述消息正文。<br></li><li>一个空行指示所有关于请求的元数据已经发送完毕。<br></li><li>一个可选的包含请求相关数据的正文 (比如HTML表单内容), 或者响应相关的文档。 正文的大小由HTTP头来指定。<br><br></li></ol>起始行和 HTTP 消息中的HTTP 头统称为请求头,而其有效负载被称为消息正文。<br>
<br>
HTTP/1.x 报文<br>在性能上的缺点
<ol><li>Header 不像 body,它不会被压缩。<br></li><li>两个报文之间的 header 通常非常相似,但它们仍然在连接中重复传输。<br></li><li>无法复用。当在同一个服务器打开几个连接时TCP 热连接比冷连接更加有效。<br></li></ol>
HTTP/2 引入了一个<b>额外的步骤</b>:它将 HTTP/1.x 消息分成帧并嵌入到流 (stream) 中。<br><b>数据帧和报头帧分离</b>,这允许<b>报头压缩</b>。<br><b>多个流可以组合</b>,这是一个被称为<b>多路复用</b> (multiplexing) 的过程,它允许更有效的底层 TCP 连接。<br>
HTTP headers
常用 headers
缓存相关
新鲜度
Cache-control<br>&<br>Age
Cache-control: max-age=N<br>通用消息头<br>
被用于在http请求和响应中,通过指定指令来实现缓存机制。<br>缓存指令是单向的,这意味着在请求中设置的指令,不一定被包含在响应中。<br>
语法
缓存请求指令
<b>Cache-Control: max-age=<seconds> <br>设置缓存存储的最大周期,超过这个时间缓存被认为过期(单位秒)。时间是相对于请求的时间。<br></b><br>Cache-Control: max-stale[=<seconds>]<br>Cache-Control: min-fresh=<seconds><br>Cache-control: no-cache <br>Cache-control: no-store<br>Cache-control: no-transform<br>Cache-control: only-if-cached<br>
缓存响应指令
Cache-control: must-revalidate<br>Cache-control: no-cache<br>Cache-control: no-store<br>Cache-control: no-transform<br>Cache-control: public<br>Cache-control: private<br>Cache-control: proxy-revalidate<br><b>Cache-Control: max-age=<seconds></b><br>Cache-control: s-maxage=<seconds><br>
Age<br>响应头<br>
Age 响应头里包含消息对象在缓存代理中存贮的时长,以秒为单位。.<br><br>Age消息头的值通常接近于0,这表示此消息对象刚刚从原始服务器获取不久;<br>其他的值则是表示代理服务器当前的系统时间与缓存的应答消息中的通用消息头 Date 的值之差。<br>
Age: <delta-seconds>
Expires<br>&<br>Date
Expires<br>响应头<br>
包含日期/时间, 即在此时候之后,响应过期。<br><br>无效的日期,比如 0, 代表着过去的日期,即该资源已经过期。<br><br><b><font color="#c41230">如果在 Cache-Control 响应头设置了 "max-age" 或者 "s-max-age" 指令,那么 Expires 头会被忽略。</font></b><br>
Expires: <http-date><br><br>Expires: Wed, 21 Oct 2015 07:28:00 GMT<br>
Date<br>通用头<br>
包含了报文创建的日期和时间。<br>
Date: <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT<br><br>Date: Wed, 21 Oct 2015 07:28:00 GMT <br>
Last-Modified<br>&<br>Date
Last-Modified<br>响应头<br>
其中包含源头服务器认定的资源做出修改的日期及时间。 <br>它通常被用作一个验证器来判断接收到的或者存储的资源是否彼此一致。<br>由于精确度比 ETag 要低,所以这是一个备用机制。<br><br>如果响应头里含有这个信息,客户端可以在后续的请求中带上 <b>If-Modified-Since</b> 来验证缓存。<br>
Date
缓存验证
Etag<br> & <br>If-None-Match<br>
ETag<br>响应头<br>
是资源的特定版本的标识符。<br><b>这可以让缓存更高效,并节省带宽,因为如果内容没有改变,Web服务器不需要发送完整的响应。<br>而如果内容发生了变化,使用ETag有助于防止资源的同时更新相互覆盖(“空中碰撞”)。</b><br><br>如果给定URL中的资源更改,则一定要生成新的Etag值。 <br>因此Etags类似于指纹,也可能被某些服务器用于跟踪。 <br>可能被跟踪服务器永久存留。<br><br>如果资源请求的响应头里含有 ETag, 客户端可以在后续的请求的头中带上 <b>If-None-Match</b> 头来验证缓存。<br>
ETag: W/"<etag_value>"<br>ETag: "<etag_value>"<br>
If-None-Match<br>条件式请求首部<br>
对于 GET 和 HEAD 请求方法来说,当且仅当服务器上没有任何资源的 ETag 属性值与这个首部中列出的相匹配的时候,服务器端会才返回所请求的资源,响应码为 200 。<br>对于其他方法来说,当且仅当最终确认没有已存在的资源的 ETag 属性值与这个首部中所列出的相匹配的时候,才会对请求进行相应的处理。<br><br>对于 GET 和 HEAD 方法来说,当验证失败的时候,服务器端必须返回响应码 304 (Not Modified,未改变)。<br>对于能够引发服务器状态改变的方法,则返回 412 (Precondition Failed,前置条件失败)。<br>需要注意的是,服务器端在生成状态码为 304 的响应的时候,必须同时生成以下会存在于对应的 200 响应中的首部中的其中一种:<br>Cache-Control、Content-Location、Date、ETag、Expires 和 Vary 。<br><br>ETag 属性之间的比较采用的是弱比较算法,即两个文件并不需要每个比特都相同。<br>例如,如果两个页面仅仅在页脚的生成时间有所不同,就可以认为二者是相同的。<br><br>当与 If-Modified-Since 一同使用的时候,If-None-Match 优先级更高(假如服务器支持的话)。<br><br>以下是两个常见的应用场景:<ol><li>采用 GET 或 HEAD 方法,来更新拥有特定的 ETag 属性值的缓存。<br></li><li>采用其他方法,尤其是 PUT,将 If-None-Match 的值设置为 * ,用来保存事先并不知道是否存在的文件,确保先前并没有进行过类似的上传操作,防止之前操作数据的丢失。这个问题属于更新丢失问题的一种。<br></li></ol>
If-None-Match: <etag_value><br>If-None-Match: <etag_value>, <etag_value>, …<br>If-None-Match: *<br>
Last-Modified<br>&<br>If-Modified-Since
Last-Modified
If-Modified-Since<br>条件式请求首部<br>
服务器只在所请求的资源在给定的日期时间之后对内容进行过修改的情况下才会将资源返回,状态码为 200 。<br>如果请求的资源从那时起未经修改,那么返回一个不带有消息主体的 304 响应;在 Last-Modified 首部中会带有上次修改时间。 <br>不同于 If-Unmodified-Since, If-Modified-Since 只可以用在 GET 或 HEAD 请求中。<br><br>当与 If-None-Match 一同出现时,它(If-Modified-Since)会被忽略掉,除非服务器不支持 If-None-Match。<br><br>最常见的应用场景是来更新<b>没有特定 ETag 标签</b>的缓存实体。<br>
If-Modified-Since: <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT
cookie 相关
Set-Cookie
<b>响应头</b>
Cookie
<b>请求头</b>
其他普遍用到的
请求头
Host
Host 请求头指明了服务器的域名(对于虚拟主机来说),以及(可选的)服务器监听的TCP端口号。
Host: <host>:<port>
User-Agent
User-Agent 请求首部是一个特征字符串,<br>用来让网络协议的对端来识别发起请求的用户代理软件的应用类型、操作系统、软件开发商以及版本号。<br>
User-Agent: <product> / <product-version> <comment>
Accept
Accept 请求头用来告知(服务器)客户端可以处理的内容类型,这种内容类型用MIME类型来表示。
Accept: <MIME_type>/<MIME_subtype><br>Accept: <MIME_type>/*<br>Accept: */*<br><br>// Multiple types, weighted with the quality value syntax:<br>Accept: text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8<br>
Accept-Language
Accept-Language 请求头允许客户端声明它可以理解的自然语言,以及优先选择的区域方言。
Accept-Language: <language><br>Accept-Language: *<br><br>// Multiple types, weighted with the quality value syntax:<br>Accept-Language: fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5<br>
Accept-Encoding
HTTP 请求头 Accept-Encoding 会将客户端能够理解的内容编码方式<br>——通常是某种压缩算法——进行通知(给服务端)。<br>
Accept-Encoding: gzip<br>Accept-Encoding: compress<br>Accept-Encoding: deflate<br>Accept-Encoding: br<br>Accept-Encoding: identity<br>Accept-Encoding: *<br><br>// Multiple algorithms, weighted with the quality value syntax:<br>Accept-Encoding: deflate, gzip;q=1.0, *;q=0.5<br>
响应头
Server
Server 首部包含了处理请求的源头服务器所用到的软件相关信息。
Server: <product>
Age
Age 消息头里包含 消息对象在缓存代理中存贮的 <b>时长</b>,以秒为单位。.
Age: <delta-seconds><br><br>Age: 24<br>
通用头
Connection
Connection 头(header) 决定当前的事务完成后,是否会关闭网络连接。<br><br>如果该值是“keep-alive”,网络连接就是持久的,不会关闭,<br>使得对同一个服务器的请求可以继续在该连接上完成。<br>
Connection-specific header fields such as Connection<br> <b>must not be used with HTTP/2.</b><br>
Connection: keep-alive<br>Connection: close<br>
Date
Date 是一个通用首部,其中包含了报文创建的日期和时间。
Date: <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT<br><br>Date: Wed, 21 Oct 2015 07:28:00 GMT <br>
Keep-Alive
Keep-Alive 是一个通用消息头,允许消息发送者提示连接的状态,<br>用来设置超时时长和最大请求数。<br>
Keep-Alive: timeout=5, max=1000
实体头
Content-Type
用于指示资源的媒体类型( media type) 。
Content-Type: text/html; charset=utf-8<br>Content-Type: multipart/form-data; boundary=something<br>
Content-Length
用来指明发送给接收方的消息主体的大小,以字节为单位。
Content-Length: <length>
HTTP 缓存
缓存是一种<b>保存 资源副本</b> 并在下次请求时直接 <b>使用该副本</b> 的技术。
缓存的类型
(私有)浏览器缓存
私有缓存只能用于单独用户。<br><br>你可能已经见过浏览器设置中的“缓存”选项。浏览器缓存拥有<b>用户通过 HTTP 下载的所有文档</b>。<br>这些缓存为浏览过的文档提供 <b>向后/向前导航</b>,<b>保存网页</b>,<b>查看源码</b>等功能,可以避免再次向服务器发起多余的请求。它同样可以提供 <b>缓存内容的离线浏览</b>。<br>
(共享)代理缓存
共享缓存可以被多个用户使用。<br><br>例如,ISP 或你所在的公司可能会架设一个 web 代理来作为本地网络基础的一部分提供给用户。<br>这样 <b>热门的资源就会被重复使用</b>,减少网络拥堵与延迟。<br>
缓存操作的目标
常见的 HTTP 缓存只能<b>存储 GET 响应</b>。<br>primary cache key 包括 request method 和目标URI(oftentimes only the URI is used as only GET requests are caching targets)。<br> <br>常见的缓存案例:<br><ul><li>一个检索请求的成功响应: 一个包含例如HTML文档,图片,或者文件的 200(OK) 响应。<br></li><li>永久重定向: 一个 301 响应。<br></li><li>错误响应: 一个 404 结果页面。<br></li><li>不完全的响应: 一个 206(Partial Content) 响应。<br></li><li>Responses other than GET if something suitable for use as a cache key is defined.<br></li></ul>
缓存控制
Cache-control 头
新鲜度<br>(强缓存)
理论上来讲,当一个资源被缓存存储后,该资源应该可以被永久存储在缓存中。<br><br>由于缓存只有有限的空间用于存储资源副本,所以缓存会定期地将一些副本删除,这个过程叫做 <b><font color="#0076b3">缓存驱逐</font></b>。<br><br>另一方面,当服务器上面的资源进行了更新,那么缓存中的对应资源也应该被更新,<br>由于HTTP是C/S模式的协议,服务器更新一个资源时,不可能直接通知客户端更新缓存,<br>所以双方必须为该资源约定一个过期时间,在该 <b><font color="#0076b3">过期时间之前</font></b>,该资源(缓存副本)就是 <b>新鲜的</b>,<br>当 <font color="#0076b3" style="font-weight: bold;">过了过期时间后</font><b>,</b>该资源(缓存副本)则变为 <b>陈旧的。</b>驱逐算法中新鲜的资源被优先保留。<br>
freshness lifetime 的计算<br>是基于几个 headers 的<br>
Cache-control: max-age=N
If a "Cache-control: max-age=N" header is specified, <br>then <b>the freshness lifetime is equal to N</b>.<br>
如果没有 Cache-control:max-age=N header,<br>检查 <b>Expires header </b>是否存在
If an Expires header exists, <br>then <b><font color="#0076b3">its value minus the value of the Date header</font></b> <br>determines the freshness lifetime. <br>
以上两个 headers 都没有,<br>检查 <b>Last-Modified</b> header
If this header is present, <br>then the cache's freshness lifetime is equal to <br><b>the value of the <font color="#0076b3">Date header minus </font><font color="#5c5c5c">the value of the</font><font color="#0076b3"> Last-modified header</font> divided by 10</b>.<br>
<font color="#0076b3">expiration time</font> 的计算
expirationTime = responseTime + freshnessLifetime - currentAge
缓存对于<br>对应新鲜与不新鲜资源<br>请求的处理<br>
当缓存接收到一个<b>对应新鲜资源的请求,</b>缓存代理不会向服务器发送请求,会直接从缓存中读取资源。<br>在 chrome 控制台的 Network选项中可以看到该请求返回 Status Code: 200 (from disk cache)。<br>
当缓存接收到一个<b>对应陈旧资源的请求</b>,缓存会 <b>先将此请求<font color="#0076b3">附加一个 If-None-Match</font> 头</b>,<b>然后发给目标服务器</b>,<br>以此来检查该资源副本是否是依然还是算新鲜的。这里即走了下面 缓存验证 的流程。<br>若服务器返回了 304 (Not Modified)(该响应不会有带有实体信息),表示此资源副本是新鲜的,这样一来,可以节省一些带宽。<br>若服务器通过 If-None-Match 或 If-Modified-Since判断后发现已过期,那么会带有该资源的实体内容返回。<br>
缓存验证<br>(协商缓存)
当缓存的文档过期后,需要进行缓存验证或者重新获取资源。<br>只有在服务器返回 强校验器 或者 弱校验器 时才会进行验证。<br>
什么时候触发验证
<ol><li>用户点击<b><font color="#0076b3"> F5</font></b> 或者 <b><font color="#0076b3">刷新按钮</font></b> 时会开始缓存验证。<br></li><li>如果缓存的响应里含有"Cache-control: must-revalidate” header,在浏览的过程中也会触发缓存验证。<br></li><li>在浏览器偏好设置里设置Advanced->Cache为强制验证缓存也能达到相同的效果。<br></li></ol>
强弱校验器
强校验器
ETag
ETag <b>响应头 </b>是一个对用户代理(User Agent, 下面简称UA)不透明的值。对于像浏览器这样的HTTP UA,不知道ETag代表什么,不能预测它的值是多少。如果资源请求的响应头里含有 ETag, <b>客户端</b>可以在后续的请求的头中<b><font color="#0076b3">带上 If-None-Match</font></b> 头来验证缓存。
弱校验器
Last-Modified
Last-Modified <b>响应头 </b>可以作为一种弱校验器。<br>说它<b>弱</b>是因为它<b><font color="#0076b3">只能精确到一秒</font></b>。<br>如果响应头里含有这个信息,<b>客户端</b>可以在后续的请求中<b><font color="#0076b3">带上 If-Modified-Since</font></b> 来验证缓存。<br>
When a validation request is made, the server can<b> either ignore</b> the validation request and<b> response with a normal 200 OK</b>, <br>or it can<b> return 304 Not Modified </b>(with an empty body) to<b> instruct the browser to use its cached copy</b>. <br>The latter response can also include headers that update the expiration time of the cached document.<br>
带 Vary 头的响应
Vary HTTP 响应头决定了对于后续的请求头,如何判断是请求一个新的资源还是使用缓存的文件。<br><br>当缓存服务器收到一个请求,其对应了一个有 vary header 的缓存响应时,<br>只有当 <b>Vary</b> header 中提到的<b>所有 header 字段</b>在<b>新请求与缓存请求中都匹配</b>时才能使用缓存的响应。<br>
使用vary头有利于内容服务的动态多样性。<br><br>例如,使用<b><font color="#0076b3"> Vary: User-Agent</font></b> 头,缓存服务器需要通过UA判断是否使用缓存的页面。<br><b><font color="#0076b3">如果需要区分移动端和桌面端的展示内容,利用这种方式就能避免在不同的终端展示错误的布局。<br></font></b>另外,它可以帮助 Google 或者其他搜索引擎更好地发现页面的移动版本,并且告诉搜索引擎没有引入Cloaking(Cloaking is a search engine optimization (SEO) technique in which the content presented to the search engine spider is different from that presented to the user's browser. )。<br>
浏览器缓存刷新
1. <b><font color="#16884a">在地址栏中输入网址后按回车或点击转到按钮</font></b><br><br>浏览器<b>以最少的请求来获取网页的数据</b>,浏览器会<b>对所有没有过期的内容 直接使用本地缓存</b>,从而减少对浏览器的请求。<br><b>Cache-control:max-age=N header,Expires header <font color="#924517">强缓存依然有效</font></b>。<br>
2. <font color="#0076b3"> </font><b><font color="#16884a">按F5或浏览器刷新按钮</font></b><br><br>浏览器会在请求中<b><font color="#924517">附加必要的缓存协商</font></b>,但<b><font color="#924517">不允许浏览器直接使用本地缓存</font><font color="#0076b3">。</font></b><br>ETag、Last-Modified 依然有效,但是 Cache-control:max-age=N ,Expires 失效。<br>
3. <b><font color="#0076b3"> </font><font color="#16884a">按 Ctrl+F5 或按Ctrl并点击刷新按钮</font><br></b><br>这种方式就是<b><font color="#924517">强制刷新</font></b>,总会发起一个全新的请求,<b><font color="#924517">不使用任何缓存</font></b>。<br>
0 条评论
下一页