这篇文章主要了解一下 HTTP
协议中定长包体传输的格式和不定长包体传输的格式,而后简单介绍一下 HTTP
协议中缓存的工做原理和应用场景。浏览器
请求或者响应均可以携带包体,基于 ABNF
描述的格式以下:缓存
#message-body = *OCTET:二进制字节流 HTTP-message = start-line *(header-field CRLF) CRLF [message-body]
HEAD
方法请求时对应的响应不能携带包体。1xx
、204
、304
状态码对应的响应。CONNECT
方法对应的 2xx
响应。在发送 HTTP
消息时已经可以肯定包体的所有长度,格式以下:服务器
#使用 Content-Length 头部明确指明包体长度 Content-Length = 1*DIGIT
Tips:1*DIGIT
表示用1
个 十进制(不是十六进制)数表示包体中的字节个数,必须与实际传输的包体长度一致,它的优势是接收端处理简单。
发送 HTTP
消息时不能肯定包体的所有长度,须要使用 Transfer-Encoding
头部指明使用 Chunk
传输方式,含有 Transfer-Encoding
头部后 Content-Length
头部会被忽略。不定长包体优势以下:网络
Trailer
头部。transfer-coding = "chunked" / "compress" / "deflate" / "gzip" / transfer-extension Chunked transfer encoding 分块传输编码:Transfer-Encoding:chunked chunked-body = *chunk last-chunk trailer-part CRLF chunk = chunk-size[chunk-ext] CRLF chunk-data CRLF #chunk-size-1*HEXDIG:注意这里是十六进制 chunk-data-1*OCTET last-chunk = 1*("0")[chunk-ext] CRLF trailer-part = *(header-field CRLF)
以下图所示,以百度首页为例,展现了 HTTP
缓存场景:curl
Tips:disk cache
表示磁盘缓存,下次访问的时候不须要下载,能够直接去磁盘获取,memory cache
表示缓存存在内存中,当浏览器退出进程时,内存中的数据会被清空。
Tips:以HTTP
请求中部分信息(如schema、path、host
)构成的字典,HTTP
响应消息构成的LRU
链表。
判断缓存是够过时可使用以下格式的公式计算:ide
#freshness_lifetime:按优先级,取如下响应头部的值 #s-maxage > max-age > Expires > 预估过时时间 # Cache-Control:s-maxage=3600 # Cache-control:max-age=86400 # Expires:Fri,03 May 2019 03:15:20 GMT # Expires-HTTP-date,指明缓存的绝对过时时间 response_is_fresh = (freshness_lifetime > current_age)
freshness_lifetime
以下图所示:编码
下面给出各类缓存时间请求统计占比状况:url
Tips:缓存的预估时间计算参照RFC7234
文档中(DownloadTime-LastModified)*10%
。
Age
头部表示来自原服务器发出响应(或者验证过时缓存),到使用缓存的响应发出时通过的秒数,对于代理服务器管理的共享缓存,客户端能够根据 Age
头部判断缓存时间,格式以下:spa
Age = delta-seconds
:current_age = corrected_initial_age + resident_time
步骤1:从浏览器复制一个缓存相关的请求命令:
以下图所示,能够在百度首页显示有缓存的资源右键复制出相关的 HTTP
请求的 curl
命令:
命令以下:代理
curl 'https://dss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/js/min_notice-816c20c940.js' -H 'Referer: https://www.baidu.com/' -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36' --compressed -I
Tips:命令最后增长一个
-I
表示返回输出头部内容。
请求结果以下图:
步骤2:使用 If-None-Match
条件判断请求内容是否过时:
curl 'https://dss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/js/min_notice-816c20c940.js' -H 'Referer: https://www.baidu.com/' -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36' --compressed -H 'If-None-Match' -I
以下图所示:
Tips:HTTP
请求时带上If-None-Match
能够判断Etag
指纹对应缓存内的容是否过时,若返回304
表示缓存能够继续使用。
Cache-Control
在 ABNF
中的秒数以下:
Cache-Control = 1#cache-directive cache-directive = token ["=" (token / quoted-string)] delta-seconds = 1*DIGIT
Tips:RFC
规范中的要求是至少能支持到2147483648(2^31)
。
请求中 Cache-Control
的取值有 max-age
、max-stale
、min-fresh
、no-cache
、no-store
、no-tansform
、only-if-cached
,它们的含义以下:
Age
超出 max-age
秒的缓存。max-stale
时,客户端仍打算使用,若 max-stale
后没有值,则表示不管过时多久客户端均可使用。Age
至少通过 min-fresh
秒后缓存才可使用。304
验证返回码才可以使用现有缓存。响应中 Cache-Control
的取值有 max-age
、s-maxage
、must-revalidate
、proxy-revalidate
、no-cache
、no-store
、no-transform
、public
、private
,它们的含义以下:
must-revalidate
相似,但它仅对代理服务器的共享缓存有效。304
返回码。若是 no-cache
后指定头部,则客户端的后续请求及响应中不含有这些头则可直接使用缓存。Age
超出 max-age
秒后则缓存过时。max-age
类似,但仅针对共享缓存,且优先级高于 max-age
和 Expires
。private
后指定头部,则在告诉代理服务器不能缓存指定的头部,但可缓存其余部分。HTTP
响应会被缓存no-store
Expires、max-age、s-maxage、public #当响应中没有明确指示过时时间的头部时,若是响应码很是明确,也能够缓存
不含有 private 不含有 Authorization
URI
做为主要的缓存关键字,当一个 URI
同时对应多份缓存时,选择日期最近的缓存。例如 Nginx
中默认的缓存关键字:proxy_cache_key
$scheme$proxy_host$request_uri;
Vary
头部指定的头部必须与请求中的头部相匹配:Vary = "*" / 1#field-name vary:*意味着必定匹配失败
no-cache
头部(Pragma:no-cache或者Cache-Control:no-cache)#新鲜的 #缓存中的响应头部明确告知可使用过时的响应(如 Cache-Control:max-stale=60) #使用条件请求去服务器端验证请求是否过时,获得 304 响应
扫码关注爱因诗贤