HTTP与WebSocket

如何在用户不做任何操作的情况下,网页能收到消息并发生变更?

一、HTTP轮询

HTTP轮询是指网页中的前端代码不断定时发送HTTP请求到服务器,服务器收到请求后给客户端响应消息。

最常见的就是扫码登录。

1.1 使用HTTP定时轮询

HTTP定时轮询是指HTTP不断定时发送请求,时间一般比较短

但是这样会有两个比较明显的问题:

  • 请求过于频繁,浪费资源
  • 请求过于频繁,用户体验不好

1.2 使用HTTP长轮询

HTTP长轮询是指将超时设置很大,比如30秒,在这30秒之内只要服务器收到了扫码请求,就立马返回客户端网页。如果超时,就立马发起下一次请求。

这种方式对于这种简单的扫码场景还可以,但是如果像网页游戏那种需要大量数据交互的场景,HTTP长轮询就不太适合了。

这时就需要使用WebSocket了。

二、WebSocket

TCP连接支持全双工通信,但是基于TCP协议的HTTP协议确是半双工通信。这是由于HTTP设计之初考虑的是看看网页文本的场景,没有考虑到这种需要客户端和服务端之间都要互相主动发送大量数据的场景。

WebSocket是一种网络通信协议,提供了全双工通信通道,可以在单个TCP连接上进行双向通信。

2.1 WebSocket的建立

WebSocket的建立过程如下:

浏览器在进行TCP三次握手建立连接之后,都统一使用HTTP协议先进行一次通信。

  • 如果此时是普通的HTTP请求,那后续双方还是使用HTTP协议进行交互。

  • 如果这时候想建立WebSocket连接,就会在HTTP请求中带上一些特殊的header头,如下:

1
2
3
Connection: Upgrade
Upgrade: WebSocket
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n

这些header头的意思是:浏览器想升级协议(Connection: Upgrade),并且想升级成WebScoket协议(Upgrade: WebSocket),同时带上一段随机生成的base64码(Sec-WebSocket-Key),发送给服务器。

如果服务器也支持WebSocket协议,并且同意升级协议,就会走WebSocket握手流程,同时根据客户端生成的base64码,用某个公开的算法变成另一段字符串,放在HTTP响应Sec-WebSocket-Accept头中,同时带上101状态码,发回给浏览器。HTTP响应如下:

1
2
3
4
HTTP/1.1 101 Switching Protocols\r\n
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n
Upgrade: WebSocket\r\n
Connection: Upgrade\r\n

之后,浏览器也同样使用公开算法将base64码转成一段字符串,如果和服务器返回的Sec-WebSocket-Accept头中的字符串一致,就说明服务器同意升级协议了,之后双方就可以使用WebSocket协议进行通信了。

⭐ 可以说:WebSocket连接的建立是基于HTTP连接的,但是WebSocket协议不是基于HTTP协议的,因为WebSocket连接建立成功后,双方就不再使用HTTP协议进行通信了,而是使用WebSocket协议进行通信了。

2.2 WebSocket的消息格式

  • opcode字段:标志这是个什么类型的数据帧
    • 0x1:文本数据帧
    • 0x2:二进制数据帧
    • 0x8:连接关闭帧
  • payload字段:存放真正想要传输数据的长度,单位是字节
  • payload data字段:存放真正想要传输的数据内容

三、总结

  • TCP协议本身是全双工的,但是HTTP协议虽然是基于TCP的,但是是半双工的,对于大部分需要服务器主动推送数据到客户端的场景都不太友好,所以需要使用WebSocket协议。
  • 因为各个浏览器都支持HTTP协议,所以WebSocket会先利用HTTP协议加上一些特殊的header头进行握手升级操作,升级成功后就跟HTTP没关系了。