HTTP 1.1之前的实现就不讨论了,因为它们已经过时太久了,我上网的时候就已经接触不到了,所以主要说说HTTP/1.1、HTTP/2.
HTTP/1.1
HTTP/1.1协议报文简介
CRLF:
\r\n
METHOD: HTTP请求,
GET
、POST
、PUT
、DELETE
...URI: 统一资源标识符,例如
/
,/index.html
...HTTPVersion: HTTP协议的版本号,例如
HTTP/1.1
,HTTP/2
HEADERS: 请求头,例如
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/n
HTTP/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