cd ..

HTTP协议

Updated September 28, 2022 , by fzdwx | networkhttpinterview

HTTP 1.1之前的实现就不讨论了,因为它们已经过时太久了,我上网的时候就已经接触不到了,所以主要说说HTTP/1.1、HTTP/2.

HTTP/1.1

HTTP/1.1协议报文简介

CRLF: \r\n

METHOD: HTTP请求,GETPOSTPUTDELETE...

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主要新特性

  1. 默认是长连接(Connection: Keep-alive),支持一个TCP连接处理多个请求.
  2. 缓存策略,在请求头中使用Cache-Control,Expires,Last-Modified,ETag等来控制.
  3. 允许响应分块,就是上面提到的transfer-encoding: chunked,允许服务端可以多次返回响应体.

但是还是存在一定的问题,例如说如果有一个TCP连接阻塞了,还是会开启新的TCP连接进行处理请求.

H2

HTTP2中的主要概念:

  1. Connection: 一个TCP连接包含一个或多个Stream,所有的通讯都在一个TCP连接上完成.
  2. Stream: 一个可以双向通讯的数据流,包含一条或多条Message,每个数据流都一个唯一标识符以及可选的优先级信息.
  3. Message: 对应HTTP/1.1中的请求或响应,包含一条或多条Frame.
  4. Frame: 最小传输单位,它以二进制进行编码.

HTTP通讯简图

在HTTP/1.1中是有Start Line + header + body 组成的,而在H2中是由一个HEADER Frame以及多个DATA Frame组成的.

HTTP/1.1与H2报文组成的区别

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通常有两种方式:

  1. 在请求头中设置Upgrade: HTTP/2.0以及Connection: Upgrade,HTTP2-Settings等,类似升级到Websocket.
  2. 使用TLS中的ALPN(Application Layer Protocol Negotiation,应用层协议协商)中的ALPN Next Protocol 字段,在Client HelloServer Hello这个阶段就可以确定下来.

而现在的浏览器基本都是实现的方式二,即与HTTPS绑定在一起.但是如果我们不用浏览器进行访问,当然也可以不用HTTPS.

详细可参考.

为什么H2能实现并行响应请求?

在HTTP/1.1中,请求与响应是一一对应的,在同一个连接里,客户端依次发送两个请求,一段时间以后收到来自服务器的一个响应,这个响应一定是对应于第一个发出去的请求的. 因为没有一个标志来表示哪个响应对应哪个请求.

而在H2中基于StreamFrame的设计: 每个Frame都带有Stream Id来标识是否为同一个Stream里面的数据,每个Stream 互不影响,这样就能做到在一个TCP里面连接里面传输多对请求/响应.

H2的新特性

H2的对HTTP/1.1优化的核心就是 使用尽可能少的连接数.

  1. 多路复用: 只用一个TCP连接就能处理多对 请求/响应 ,不用在开启另外的TCP连接,就是通过StreamFrame来实现的.
  2. 二进制分帧: 使用Frame为最小单位进行通讯,并采用二进制编码.
  3. 头部压缩: 使用HPACK算法进行优化.
    • 维护一份相同的静态字典,包含常见的请求头的KV组合
    • 一份动态字典,可以动态的扩容(每个连接单独维护)
    • 支持哈夫曼编码(静态哈夫曼码表)

    在HTTP/1中消息体可以用gzip进行压缩,但是请求头通常没有任何压缩,有时候请求头的数据可能比请求体的数据还多.

  4. 请求优先级: 一般在HEADERS帧与PRIORITY帧中携带,通常依赖于服务端的支持程度.

工具

生成测试签名

go run $GOROOT/src/crypto/tls/generate_cert.go --host localhost

使用curl调试HTTPS

curl https://zcygov.cn -vv