HTTP 1.1之前的实现就不讨论了,因为它们已经过时太久了,我上网的时候就已经接触不到了,所以主要说说HTTP/1.1、HTTP/2.
HTTP/1.1
HTTP/1.1协议报文简介
CRLF:
\r\nMETHOD: HTTP请求,
GET、POST、PUT、DELETE...URI: 统一资源标识符,例如
/,/index.html...HTTPVersion: HTTP协议的版本号,例如
HTTP/1.1,HTTP/2HEADERS: 请求头,例如
Host:localhost,Accept: */*.BODY: 请求体,例如说一个JSON数据
{"name":"fzdwx"}HTTPStatus: HTTP响应状态,常见的有
200,404等HTTPStatusDesc: HTTP响应状态描述,
200对应的OK.
请求
METHOD<SPACE>URI<SPACE>HTTPVersion
HEADERS
<CRLF>
BODY
示例:
GET /hello HTTP/1.1
Host: 192.168.1.107:8889
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.82 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9响应
HTTPVersion HTTPStatus HTTPStatusDesc
HEADERS
<CRLF>
BODY
示例:
如果响应中使用了
transfer-encoding: chunked这个来替代Content-Length,就表示这是一个不固定大小的响应,结尾通常用0\r\n来分割.
HTTP/1.1 200 OK
transfer-encoding: chunked
content-type: application/json; charset=utf-8
0/r/nHTTP/1.1主要新特性
- 默认是长连接(Connection: Keep-alive),支持一个TCP连接处理多个请求.
- 缓存策略,在请求头中使用Cache-Control,Expires,Last-Modified,ETag等来控制.
- 允许响应分块,就是上面提到的transfer-encoding: chunked,允许服务端可以多次返回响应体.
但是还是存在一定的问题,例如说如果有一个TCP连接阻塞了,还是会开启新的TCP连接进行处理请求.
H2
HTTP2中的主要概念:
- Connection: 一个TCP连接包含一个或多个- Stream,所有的通讯都在一个TCP连接上完成.
- Stream: 一个可以双向通讯的数据流,包含一条或多条- Message,每个数据流都一个唯一标识符以及可选的优先级信息.
- Message: 对应HTTP/1.1中的请求或响应,包含一条或多条- Frame.
- Frame: 最小传输单位,它以二进制进行编码.
在HTTP/1.1中是有Start Line + header + body 组成的,而在H2中是由一个HEADER Frame以及多个DATA Frame组成的.

Frame
通常有一些公共的字段,例如Length,Type,Flags以及Stream Id;也各个类型所独有的字段.
分类如下:
- DATA: 用于传输http消息体.
- HEADERS: 用于传输首部字段.
- PRIORITY: 用于指定或重新指定引用资源的优先级.
- RST_STREAM: 用于通知流的非正常终止.
- SETTINGS: 用于约定客户端和服务端的配置数据.例如设置初识的双向流量控制窗口大小.
- PUSH_PROMISE: 服务端推送许可.
- PING: 用于计算往返时间,执行“ 活性” 检活.
- GOAWAY: 用于通知对端停止在当前连接中创建流.
- WINDOW_UPDATE: 用于调整个别流或个别连接的流量.
- CONTINUATION: 专门用于传递较大 HTTP 头部时的持续帧.
为什么H2必须要走HTTPS?
这其实在H2标准中没有规定,主要是为了更方便的进行HTTP协议的 升级/协商,确认一个Web服务器是否支持H2通常有两种方式:
- 在请求头中设置Upgrade: HTTP/2.0以及Connection: Upgrade,HTTP2-Settings等,类似升级到Websocket.
- 使用TLS中的ALPN(Application Layer Protocol Negotiation,应用层协议协商)中的ALPN Next Protocol字段,在Client Hello与Server Hello这个阶段就可以确定下来.
而现在的浏览器基本都是实现的方式二,即与HTTPS绑定在一起.但是如果我们不用浏览器进行访问,当然也可以不用HTTPS.
详细可参考.
为什么H2能实现并行响应请求?
在HTTP/1.1中,请求与响应是一一对应的,在同一个连接里,客户端依次发送两个请求,一段时间以后收到来自服务器的一个响应,这个响应一定是对应于第一个发出去的请求的. 因为没有一个标志来表示哪个响应对应哪个请求.
而在H2中基于Stream和Frame的设计: 每个Frame都带有Stream Id来标识是否为同一个Stream里面的数据,每个Stream
互不影响,这样就能做到在一个TCP里面连接里面传输多对请求/响应.
H2的新特性
H2的对HTTP/1.1优化的核心就是 使用尽可能少的连接数.
- 多路复用: 只用一个TCP连接就能处理多对 请求/响应 ,不用在开启另外的TCP连接,就是通过Stream与Frame来实现的.
- 二进制分帧: 使用Frame为最小单位进行通讯,并采用二进制编码.
- 头部压缩: 使用HPACK算法进行优化.在HTTP/1中消息体可以用gzip进行压缩,但是请求头通常没有任何压缩,有时候请求头的数据可能比请求体的数据还多. 
- 请求优先级: 一般在HEADERS帧与PRIORITY帧中携带,通常依赖于服务端的支持程度.
工具
生成测试签名
go run $GOROOT/src/crypto/tls/generate_cert.go --host localhost使用curl调试HTTPS
curl https://zcygov.cn -vv