WebSocket
WebSocket 是一个双向通信协议,它在握手阶段采用 HTTP/1.1 协议(暂时不支持 HTTP/2)。
握手过程如下:
- 首先客户端向服务端发起一个特殊的 HTTP 请求,其消息头如下:
GET /chat HTTP/1.1 // 请求行
Host: server.example.com
Upgrade: websocket // required
Connection: Upgrade // required
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== // required
Origin: http://example.com // 用于防止未认证的跨域脚本使用浏览器 websocket api 与服务端进行通信
Sec-WebSocket-Protocol: chat, superchat // optional, 子协议协商字段
Sec-WebSocket-Version: 13
- 如果服务端支持该版本的 WebSocket,会返回 101 响应,响应标头如下:
HTTP/1.1 101 Switching Protocols // 状态行
Upgrade: websocket // required
Connection: Upgrade // required
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= // required,加密后的 Sec-WebSocket-Key
Sec-WebSocket-Protocol: chat // 表明选择的子协议
握手完成后,接下来的 TCP 数据包就都是 WebSocket 协议的帧了。
可以看到,这里的握手不是 TCP 的握手,而是在 TCP 连接内部,从 HTTP/1.1 upgrade 到 WebSocket 的握手。
WebSocket 提供两种协议:不加密的 ws://
和 加密的 wss://
.
在 Python 编程中,可使用 websockets 实现的异步 WebSocket 客户端与服务端。
如果是写 Web 应用,可使用 Flask-SocketIO,它底层实现了 WebSocket 和 long-polling 两种通信方式。
HTTP/2
HTTP/2 于 2015 年标准化,主要目的是优化性能。其特性如下:
- 二进制协议:HTTP/2 的消息头使用二进制格式,而非文本格式。并且使用专门设计的 HPack 算法压缩。
- 多路复用(Multiplexing):就是说 HTTP/1 可以重复使用同一个 TCP 连接,并且连接是多路的,多个请求或响应可以同时传输。
- 服务器推送:服务端能够直接把资源推送给客户端,当客户端需要这些文件的时候,它已经在客户端了。(该推送对 Web App 是隐藏的,由浏览器处理)
- HTTP/2 允许取消某个正在传输的数据流(通过发送 RST_STREAM 帧),而不关闭 TCP 连接。
它允许服务端将资源推送到客户端缓存,我们访问淘宝等网站时,经常会发现很多请求的请求头部分会提示“provisional headers are shown”,这通常就是直接从缓存加载了资源,因此请求根本没有被发送。观察 Chrome Network 的 Size 列,这种请求的该字段一般都是 from disk cache
或者 from memroy cache
.
Chrome 可以通过如下方式查看请求使用的协议:
2019-02-10: 使用 Chrome 查看,目前主流网站基本都已经部分使用了 HTTP/2,知乎、bilibili、GIthub 使用了
wss
协议,也有很多网站使用了 SSE(格式如data:image/png;base64,<base64 string>
)
而且很多网站都有使用 HTTP/2 + QUIC,该协议的新名称是 HTTP/3,它是基于 UDP 的 HTTP 协议。
WebSocket 与 HTTP/2 比较
- 加密与否:
- WebSocket 支持明文通信
ws://
和加密wss://
, - 而 HTTP/2 协议虽然没有规定必须加密,但是主流浏览器都支持 HTTP/2 over TLS.
- WebSocket 支持明文通信
- 消息推送:
- WebSocket是全双工通道,可以双向通信。而且消息是直接推送给 Web App.
- HTTP/2 虽然也支持 Server Push,但是服务器只能主动将资源推送到客户端缓存!并不允许将数据推送到客户端里跑的 Web App 本身。服务器推送只能由浏览器处理,不会在应用程序代码中弹出服务器数据,这意味着应用程序没有 API 来获取这些事件的通知。
- 为了接近实时地将数据推送给 Web App, HTTP/2 可以结合 SSE(Server-Sent Event)使用。这是一种新提出的 API,用于从服务端单向将数据推送给 Web App.
WebSocket 在需要接近实时双向通信的领域,很有用武之地。而 HTTP/2 + SSE 适合用于展示实时数据。
requests 查看 HTTP 协议版本号
可以通过 resp.raw.version
得到响应的 HTTP 版本号:
>>> import requests
>>> resp = requests.get("https://zhihu.com")
>>> resp.raw.version
11
但是 requests 默认使用 HTTP/1.1,并且不支持 HTTP/2.
参考
- 深入探索 WebSockets 和 HTTP/2
- HTTP/2 特性与抓包分析
- Can I Use HTTP/2 on Browsers
- Python 3.x how to get http version (using requests library)
- WebSocket 是什么原理?
- 原生模块打造一个简单的 WebSocket 服务器
原文地址:https://www.cnblogs.com/kirito-c/p/10360309.html