websocket
HTTP 协议有一个缺陷:通信只能有客户端发起。这种单向请求的特点,在服务器有连续状态变化需通知客户端的场景中,我们就只能轮询:每隔一段时间,就发出一个询问,了解服务器最新的信息状态。如聊天室。
轮询的效率低,且浪费资源,于是 websocket就出现了。
# websocket 协议
websocket 是web浏览器和服务器间的一种全双工通信协议。 由IETF定协议标准,API由W3C定。 一旦连接建立,之后的全部数据通信都通过这个连接进行。 可互相发送JSON、XML、HTML后图片等任意格式的数据。
# WS VS HTTP
# 相同点
- 都是基于TCP的应用层协议
- 是使用Request/Response模型建立的连接
- 在连接建立过程中错误的处理方式相同,即WS返回和HTTP相同的返回码
- 都可以在网络中传输数据
# 不同点
- WS使用HTTP来建立连接,定义了一系列新的header,HTTP不适用
- WS 的连接不能通过中间人转发,必须是一个直接连接
- WS 连接建立后,双方都可在任何时刻向对方发送数据
- WS 连接建立后,数据使用帧来传递,不再需要Request消息
- WS 的数据帧有序
# websocket 通信过程及对应报文分析
WS 整个通信过程如下图:
websocket是基于TCP的一个应用协议,与HTTP协议的关联之处在于websocket的握手数据被HTTP服务器当作HTTP包来处理,主要通过Update request HTTP包建立起连接,之后的通信全部使用websocket自己的协议。
TCP连接建立后,客户端发送websocket的握手请求,请求报文头部如下:
GET /uin=xxxxxxxx&app=xxxxxxxxx&token=XXXXXXXXXXXX HTTP/1.1
Host: server.example.cn:443
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36
Upgrade: websocket
Sec-WebSocket-Version: 13
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: user_id=XXXXX
Sec-WebSocket-Key: 1/2hTi/+eNURiekpNI4k5Q==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Protocol: binary, base64
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
- 第一行为为请求的方法,类型必须为GET,协议版本号必须大于1.1
- Upgrade字段必须包含,值为websocket
- Connection字段必须包含,值为Upgrade
- Sec-WebSocket-Key字段必须包含 ,记录着握手过程中必不可少的键值。
- Sec-WebSocket-Protocol字段必须包含 ,记录着使用的子协议
- Origin(请求头):Origin用来指明请求的来源,Origin头部主要用于保护Websocket服务器免受非授权的跨域脚本调用Websocket API的请求。也就是不想没被授权的跨域访问与服务器建立连接,服务器可以通过这个字段来判断来源的域并有选择的拒绝。

服务器接收到请求后,返回状态码为101 Switching Protocols 的响应
HTTP/1.1 101 Switching Protocols
Server: WebSockify Python/2.6.6
Date: Wed, 27 May 2020 03:03:21 GMT
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: hXXXXXXXXXXXXXXxGmM=
Sec-WebSocket-Protocol: binary
1
2
3
4
5
6
7
2
3
4
5
6
7

Sec-WebSocket-Accept字段是由握手请求中的Sec-WebSocket-Key字段生层的。
握手成功后,通信不再使用HTTP协议,而采用WebSocket独立的数据帧。如下图所示,为协议帧格式:

# nginx 支持websocket 配置
由于http 请求 涉及 反向代理 所以就涉及 nginx 配置需要支持 websocket 需要做一些特殊的配置;
# 配置Nginx支持webSocket开始
proxy_set_header Host $http_host;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
1
2
3
4
5
2
3
4
5
上次更新: 2022/11/29, 15:43:28