fzdwx

fzdwx

Hello , https://github.com/fzdwx

HTTP协议

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组成的.

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
加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。