一文说透HTTP协议
Posted 路演前端
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一文说透HTTP协议相关的知识,希望对你有一定的参考价值。
协议
由多方遵守,将初始输入由语法和语义按顺序编译(翻译)至最终目标的约定叫协议。
由此可见,协议由语法、语义和顺序三要素组成。
语法,就是这一段内容要符合一定的规则和格式。例如,括号要成对,结束要使用分号等。
语义,就是这一段内容要代表某种意义。例如数字减去数字是有意义的,数字减去文本一般来说就没有意义。
顺序 ,就是先做什么,后做什么。例如,可以先加上某个数值,然后再减去某个数值。
HTTP
超文本传输协议(HyperText Transfer Protocol)的缩写,即HTTP。
HTTP是一种用于分布式、协作式和超媒体信息系统的应用层协议,是万维网的数据通信的基础。
版本演进
HTTP/0.9
特性:
基于 TCP/IP 协议的应用层协议。不涉及数据包(packet)传输,默认使用80端口。
只接受GET一种请求方法
协议规定,服务器只能回应html格式的字符串,不能回应别的格式。
请求命令样例:
GET /index.html
TCP 连接建立后,客户端向服务器请求网页index.html。
<html>
<body>Hello World</body>
</html>
服务器发送完毕后就关闭TCP连接。
HTTP/1.0
特性:
支持发送任何格式的内容。
引入了POST命令和HEAD命令。
HTTP请求和回应的格式要求除了数据部分,每次通信都必须包括头信息(HTTP Header)。
每个TCP连接只能发送一个请求,发送数据完毕,连接就关闭。
请求命令样例:
GET / HTTP/1.0
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5)
Accept: */*
GET请求命令必须在尾部添加协议版本(HTTP/1.0)。
User-Agent描述客户端的情况。
Accept声明请求的返回可接收的数据格式。
*/*
代表接收任何数据格式。
HTTP/1.0 200 OK
Content-Type: text/plain
Content-Length: 137582
Expires: Thu, 05 Dec 1997 16:00:00 GMT
Last-Modified: Wed, 5 August 1996 15:55:28 GMT
Server: Apache 0.84
<html>
<body>Hello World</body>
</html>
回应的格式是"头信息 + 一个空行(\r\n) + 数据"。
第一行是"协议版本 + 状态码(status code) + 状态描述"。
Content-Type字段用于描述数据格式,数据类型的总称是MIME type,可在尾部使用分号,添加参数。
// 发送类型是网页,编码是UTF-8。
Content-Type: text/html; charset=utf-8
HTTP/1.1
特性:
引入了持久连接(persistent connection),即TCP连接默认不关闭,可以被多个请求复用,不用声明
Connection: keep-alive
。客户端可在最后一个请求时,发送
Connection: close
,要求服务器关闭TCP连接。对于同一个域名,大部分浏览器允许同时建立6个持久连接。
引入管道机制(pipelining),即在同一个TCP连接里面,客户端可以同时发送多个请求,但服务器还是按照顺序处理请求。
增加了对PUT、PATCH、HEAD、 OPTIONS、DELETE的支持
客户端请求的头信息新增了Host字段,用来指定服务器的域名,可以将请求发往同一台服务器上的不同网站(虚拟主机)。
Content-length
字段的作用是声明本次回应的数据长度。
使用的前提是服务器发送回应之前,必须知道回应的数据长度,才能从多个返回中知晓哪个返回属于自身的请求回应。支持分块传输编码
请求或回应的头信息有Transfer-Encoding
字段,就表明回应将由数量未定的数据块组成。
Transfer-Encoding: chunked
每个非空的数据块之前,会有一个16进制的数值,表示这个块的长度。最后是一个大小为0的块,就表示本次回应的数据发送完了,示例如下:
HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked
25
This is the data in the first chunk
1C
and this is the second one
3
con
8
sequence
0
HTTP/2
特性:
仅在HTTPS环境生效。
一个彻底的二进制协议。
头信息和数据体都是二进制,并且统称为"帧"(frame):头信息帧和数据帧。收益在于可以定义额外的帧,如果使用文本实现,解析数据将会变得非常麻烦,二进制解析则方便得多。多工
举例来说,在一个TCP连接里面,服务器同时收到了A请求和B请求,于是先回应A请求,结果发现处理过程非常耗时,于是就发送A请求已经处理好的部分, 接着回应B请求,完成后,再发送A请求剩下的部分。
这样双向的、实时的通信,就叫做多工(Multiplexing)。
HTTP/2 复用TCP连接,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应,这样就避免了"队头堵塞"。
数据流(stream)
由于多工的特性,HTTP/2 的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的回应。
HTTP/2 将每个请求或回应的所有数据包,称为一个数据流。每个数据流都有一个独一无二的编号。数据包发送的时候,都必须标记数据流ID,用来区分它属于哪个数据流。另,客户端发出的数据流,ID一律为奇数,服务器发出的,ID为偶数。
数据流可以由客户端指定优先级,优先级越高,服务器就会越早回应。
数据流可以由客户端取消,同时不关闭TCP连接。头信息压缩(header compression)
HTTP 协议不带有状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如Cookie和User Agent,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。
首次,客户端使用gzip或compress压缩头信息后发送请求;
客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号;
之后每次请求只发送索引号即可。服务器推送(server push)
HTTP/2 允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送。
假设客户端请求一个页面,该页面中包含较多图片等静态资源。
常规情况下,渲染该页面需要发送两次以上的请求才可完成。
采用server push,服务器可将页面相关静态资源主动一起发送给客户端。
理解
由客户端和服务端遵守,符合“协议”的三要素,即:
符合语法,浏览器只认可该格式。分别由状态、首部和内容组成。
符合语义,比如状态 200,表示网页成功返回。
符合顺序,浏览器通过 HTTP 请求才能拿到一串 HTTP 返回值。
知识要点
http的无状态
无状态的意义:客户端和服务器在某次会话中产生的数据不会被保留
http 协议对于事务处理没有记忆能力
对同一个url请求没有上下文关系
每次的请求都是独立的,它的执行情况和结果与前面的请求和之后的请求是无直接关系的,它不会受前面的请求应答情况直接影响,也不会直接影响后面的请求应答情况
服务器中没有保存客户端的状态,客户端必须每次带上自己的状态去请求服务器
请求过的资源下一次会继续进行请求
http-cache
减少了冗余的数据传输,减少网络花销
减少服务器端的压力
Web 缓存能够减少延迟与网络阻塞,进而减少客户端渲染耗时
本地缓存
指浏览器请求资源时命中了浏览器本地的缓存资源,浏览器并不会发送真正的请求给服务器了。
逻辑流程
第一次浏览器发送请求给服务器时,此时浏览器还没有本地缓存副本,服务器返回资源给浏览器,响应码是200 OK,浏览器收到资源后,把资源和对应的响应头一起缓存下来。
第二次浏览器准备发送请求给服务器时候,浏览器会先检查上一次服务端返回的响应头信息中的Cache-Control,它的值是一个相对值,单位为秒,表示资源在客户端缓存的最大有效期,过期时间为第一次请求的时间减去Cache-Control的值,过期时间跟当前的请求时间比较:
如果本地缓存资源没过期,那么命中缓存,不再请求服务器;
如果没有命中,浏览器就会把请求发送给服务器,进入缓存协商阶段。
在请求/响应头中由Cache-Control和Expires实现
Cache-Control
有多个可选值代表不同的意义:
no-cache:不使用本地缓存。需要使用缓存协商,先与服务器确认返回的响应是否被更改,如果之前的响应中存在ETag,那么请求的时候会与服务端验证,如果资源未被更改,则可以避免重新下载。
no-store:直接禁止游览器缓存数据,每次用户请求该资源,都会向服务器发送一个请求,每次都会下载完整的资源。
public:可以被所有的用户缓存,包括终端用户和CDN等中间代理服务器。
private:只能被终端用户的浏览器缓存,不允许CDN等中继缓存服务器对其缓存。
max-age:从当前请求开始,允许获取的响应被重用的最长时间(秒)。
Expires
一个绝对时间,时间格式是如Mon, 10 Jun 2015 21:31:12 GMT,只要发送请求时间是在Expires之前,那么本地缓存始终有效,否则就会去服务器发送请求获取新的资源。
如果同时出现Cache-Control:max-age和Expires,那么max-age优先级更高。
缓存协商
逻辑流程
当第一次请求时服务器返回的响应头中存在以下情况时
没有 Cache-Control 和 Expires
Cache-Control 和 Expires 过期了
Cache-Control 的属性设置为 no-cache
浏览器第二次请求时就会与服务器进行协商,询问浏览器中的缓存资源是不是旧版本,需不需要更新,此时,服务器就会做出判断:
如果缓存和服务端资源的最新版本是一致的,那么就无需再次下载该资源,服务端直接返回304 Not Modified 状态码;
如果服务器发现浏览器中的缓存已经是旧版本了,那么服务器就会把最新资源的完整内容返回给浏览器,状态码就是200 Ok。
根据HTTP的另外两组头信息进行判断,分别是:Last-Modified/If-Modified-Since 与 ETag/If-None-Match。
Last-Modified 与 If-Modified-Since
浏览器第一次请求资源时,服务器会把资源的最新修改时间Last-Modified:Thu, 29 Dec 2011 18:23:55 GMT放在响应头中返回给浏览器
Cache-Control:max-age=3600
Expires: Fri, Jan 12 2018 00:27:04 GMT
Last-Modified: Thu, 29 Dec 2011 18:23:55 GMT
第二次请求时,浏览器就会把上一次服务器返回的修改时间放在请求头If-Modified-Since:Thu, 29 Dec 2011 18:23:55发送给服务器。
If-Modified-Since: Thu, 29 Dec 2011 18:23:55 GMT
服务器就会拿这个时间跟服务器上的资源的最新修改时间进行对比:
如果两者相等或者大于服务器上的最新修改时间,那么表示浏览器的缓存是有效的,此时缓存会命中,服务器就不再返回内容给浏览器了,同时Last-Modified头也不会返回,因为资源没被修改,返回了也没什么意义。
如果没命中缓存则最新修改的资源连同Last-Modified头一起返回。
ETag与If-None-Match
与Last-Modified/If-Modified-Since类似,唯一的区别是它基于资源的内容的摘要信息(比如MD5 hash)来判断,好处是如果因为某种原因到时资源的修改时间没改变,那么用ETag就能区分资源是不是有被更新。
Cache-Control: public, max-age=31536000
ETag: "15f0fff99ed5aae4edffdd6496d7131f"
浏览器发送第二次请求时,会把第一次的响应头信息ETag的值放在If-None-Match的请求头中发送到服务器,与最新的资源的摘要信息对比。
If-None-Match: "15f0fff99ed5aae4edffdd6496d7131f"
如果相等,取浏览器缓存,否则内容有更新,最新的资源连同最新的摘要信息返回。
以上是关于一文说透HTTP协议的主要内容,如果未能解决你的问题,请参考以下文章