HTTP 协议的初印象:javascript
是基于 TCP/IP 协议的应用层协议,不涉及数据包的传输,主要规定了客户端和服务器之间的通讯格式,默认使用 80 端口。css
是个弱智协议,客户端发起请求之后,服务器只能返回 HTML 格式的字符串,不能回应别的格式。html
只有一个 GET 命令:java
GET /index.html
复制代码
上面命令表示,TCP 链接(connection)创建后,客户端向服务器请求(request)网页 index.html。浏览器
服务器发送完毕,就关闭 TCP 链接。缓存
与 0.9 版本相比,有如下几点变化:bash
新增的功能还有:服务器
<!-- 请求命令, 必须在尾部添加协议版本(HTTP/1.0)-->
GET /HTTP/1.0
<!-- 多行头信息,描述了客户端的状况 -->
User-Agent: Mozilla/5.0(Macintosh: Intel Mac PS X 10_10_5)
<!-- 客户端表示本身能够接受任何格式的数据 -->
Accept:*/*
复制代码
<!-- 头信息 -->
HTTP/1.0 200 OK
Content-Type: text/plain
Content-Length: 137582
Expires:Thu, 05 Dec 1997 16:00:00 GMT
Server: Apache 0.84
<!-- 数据 -->
<html>
<body>Hello World</body>
</html>
复制代码
其中,头信息的第一行是 “协议的版本 + 状态码(status code) + 状态描述”app
Content-Type 字段的做用是告诉客户端从服务端返回的数据是什么格式。ide
常见的 ContentType:
数据类型的构成包括一级类型和二级类型,中间用斜杠隔开。这些类型都被称为 MIME type。
MIME type 不只用于 HTTP 请求,也能够用于别的地方,好比 HTML 网页。
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<!-- 等同于 -->
<meta charset="utf-8" />
复制代码
客户端在请求的时候,用 Accept - Encoding 字段说明本身能够接受哪些压缩方法。
Accept-Encoding: gzip, deflate
复制代码
而服务器使用 Content-Encoding 字段说明数据的压缩方法。
Content-Encoding: gzip
Content-Encoding: compress
Content-Encoding: deflate
复制代码
每一个 TCP 链接只能发送一个请求,数据发送完毕链接就关闭了,若是要请求别的资源,必须再新建一个链接。
可是 TCP 链接的成本很高,由于客户端和服务器的三次握手,而且启动发送的速率较慢。
有一些浏览器为了解决 TCP 会关闭的问题,采用了非标准的 Connection 字段。
浏览器请求和服务器回应都带有这个字段:
Connection: keep-alive
复制代码
这样的话,一个能够复用的链接创建了,直到客户端或者服务器主动关闭链接。可是不一样的浏览器实现不一样,这不是一个好的解决办法。
相比 1.0 版,1.1 版最大的变化是保持链接,即默认 TCP 链接不关闭,能够被多个请求复用,不用再声明 Connection: keep-alive。
那怎么关闭呢?若是客户端或者服务器发现对方一段时间内没有活动,就能够主动关闭链接。不过最好仍是客户端在发送最后一个请求的时候,发送一个 Connection:close,明确要求服务器关闭 TCP 链接。
另外,对于同一个域名,大多数浏览器容许同时创建 6 个持久链接。
管道机制: 在同一个 TCP 链接里,客户端能够同时发送多个请求。
之前的作法是客户端先发送 A 请求,而后再发送 B 请求。管道机制是容许浏览器同时发送 A 请求和 B 请求,可是服务器仍是按照顺序进行的,先回应 A 请求再回应 B 请求。
一个 TCP 链接如今能够传送多个回应,势必就要有一种机制,区分数据包是属于哪个回应的。
Content-length 字段的做用,声明本次回应的数据长度。
Content-Length: 3495
复制代码
上面的字段告诉客户端,本次回应的长度是 3495 个字节,后面的字节就属于下一个回应了。
因此,使用 Content-Length 字段的前提条件是,服务器发送回应以前,必须知道回应的数据长度。
而在 1.0 版本中,这个字段能够存在,也能够不存在,由于服务端关闭了 TCP 链接说明数据包已经全了。
1.1 版新增了不少动词方法:PUT、PATCH、HEAD、OPTIONS、DELETE。
客户端的请求头信息增长了 Host 字段,用来指定服务器的域名。
这个字段能够将请求发往同一台服务器的不一样网站。
如:
Host: www.example.com
复制代码
"队头堵塞": 在 1.1 版协议中,虽然能够在一个 TCP 中发送多个请求,服务器只有处理完一个回应,才会进行下一个回应。要是前面的回应特别慢,后面就会有许多请求排队等着。
为了不这个问题,只有两种方法:一是减小请求数,二是同时多开持久链接。
因此产生了不少网页优化技巧,好比合并脚本和样式表,将图片嵌入 CSS 代码,域名分片等,可是 HTTP 协议设计得更好的话,这些工做彻底没有必要作的。
2009 年,谷歌公开了本身搞的 SPDY 协议,主要为了解决 HTTP/1.1 效率不高的问题。
这个协议最终被看成了 HTTP/2 的基础。
HTTP/2 协议不叫 HTTP/2.0,这是由于标准委员会不在打算发布子版本,下一个新的版本将会是 HTTP/3。
HTTP 协议的头确定是文本(ASCII 码),数据体能够是文本,也能够是二进制。
但 HTTP/2 协议头和数据体都是二进制,是一个不折不扣的二进制协议。
这里的头和数据体都换了一个身份叫作 “帧”:头信息帧和数据帧。
二进制协议的好处就是能够定义额外的帧,HTTP/2 有近十种帧,为未来的高级应用打好了基础,由于二进制解析比文本解析更方便。
HTTP/2 协议复用 TCP 链接,也就是说客户端和服务端能够同时发送或者回应多个请求。
好比说,在一个 TCP 里,客户端给服务端发送了 A 和 B 两个请求,按道理说应该先处理 A 请求,可是服务端发现 A 请求有点费劲儿,就先把 A 请求中处理好的发出去,接着回应 B 请求,完事儿之后再发送 A 请求中剩下的部分。
像这样双向,实时的通讯,就叫作多工(Multiplexing)。
HTTP/2 的数据包不是按照顺序发送的,同一个链接里的数据包可能属于多个请求。因此须要一个编号,这个编号指明数据包属于哪个请求或者回应。
这里有一个概念叫作数据流,咱们把一个请求或者回应的全部数据包合在一块儿称为一个数据流。每一个数据流都有一个独一无二的编号,数据包发送的时候都必须标定数据流编号。
客户端请求的数据流编号一概为基数,而服务端回应的数据流编号为偶数。
在 HTTP/1.1 中终止请求的方式只能是关闭 TCP 链接,而如今能够发送一个信号:(RST_STREAM 帧),取消这个数据流。
也就是说 HTTP/2 能够取消某一次请求,同时能保证 TCP 链接打开,能够被其余请求所使用。
此外,客户端能够指定数据流的优先级,优先级高的服务器越早响应。
由于协议不带有状态,每次请求都必须附上全部信息。有一些信息是重复的,这样会影响数据传输速度,浪费带宽。
HTTP/2 采用头信息压缩机制能够减小不利影响。首先是将信息压缩后再发送(gzip 或者 compress),其次是客户端 和服务器同时维护一张头信息表,这个表很神奇的地方在于能够利用索引进行管理,只要咱们发送索引就能够表示咱们传输的信息,这样就可以提升速度。
HTTP/2 容许服务器在没有通过容许的状况下,能够主动向客户端推送资源 。这个过程叫作服务器推送(server push)。
举一个例子,别发送邮件给咱们的时候,邮箱会冒个弹框出来告诉咱们有人往邮箱里投递了一封邮件。注意,此时咱们并无刷新网页。
服务器推送还可能用到消息提醒,静态资源自动推送到服务端等场景。