HTTP 第五章 协议升级机制

文章介绍了HTTP/1.1协议中的Upgrade机制,如何将其用于引导WebSocket连接,并提供了使用Node.js和浏览器WebSocketAPI的示例代码。重点讲述了WebSocket协议的工作原理和在实际应用中的使用情况。
摘要由CSDN通过智能技术生成

HTTP/1.1 协议提供了一种使用 Upgrade 标头字段的特殊机制,这一机制允许将一个已建立的连接升级成新的、不相容的协议。这个机制是可选的;它并不能强制协议的更改(通常来说这一机制总是由客户端发起的)。如果它们支持新协议,实现甚至可以不利用upgrade,在实践中,这种机制主要用于引导 WebSocket 连接
注意:HTTP/2 明确禁止使用此机制;这个机制只属于HTTP/1.1。

由于 HTTP/1.1 升级机制最常用的场景是 WebSocket。由于 WebSocket 是一块专业的内容,我们还是站在巨人的肩膀上实现我们的示例 demo。服务端使用 node + ws 实现 WebSocket 服务。客户端使用 浏览器 API WebSocket。

示例代码

  • 客户端
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>websocket</title>
</head>
<body>
    <button>发送消息</button>
    <script>
        const ws = new WebSocket('ws://127.0.0.1:8081');
        ws.addEventListener('open', function (event) {
            console.log('连接成功', event);
        });
        ws.addEventListener('message', function (event) {
            console.log('收到消息', event.data);
        });
        ws.addEventListener('close', function (event) {
            console.log('连接关闭', event);
        });
        ws.addEventListener('error', function (event) {
            console.log('连接错误', event);
        })
        document.querySelector('button').addEventListener('click', function () {
            ws.send('hello');
        })

    </script>
</body>
</html>
  • 服务端
const WebSocket = require('ws');

const server = new WebSocket.Server({ port: 8081 });

server.on('open', function open() {
  console.log('connected');
});

server.on('close', function close() {
  console.log('disconnected');
});

server.on('connection', function connection(ws, req) {
  const ip = req.connection.remoteAddress;
  const port = req.connection.remotePort;
  const clientName = ip + port;

  console.log('%s is connected', clientName)

  // 发送欢迎信息给客户端
  ws.send("Welcome " + clientName);

  ws.on('message', function incoming(message) {
    console.log('received: %s from %s', message, clientName);
    
    // 广播消息给所有客户端
    server.clients.forEach(function each(client) {
      if (client.readyState === WebSocket.OPEN) {
        client.send( clientName + " -> " + message);
      }
    });

  });

});

当浏览器和服务端进行连接时,向服务端发送了一个 HTTP/1.1 的 GET 请求。

  • 请求头需要说明具体的协议,可以是一个,也可以是多个。例如我们的请求报文 Upgrade: websocket 表明是 websocket 协议。
  • Sec-WebSocket-Extensions指定一个或多个请求服务器使用的协议级 WebSocket 扩展,例如: Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
  • Sec-WebSocket-Key向服务器提供确认客户端有权请求升级到 WebSocket 的所需信息,密钥的值是使用 WebSocket 规范中定义的算法计算的,不提供安全性。Sec-WebSocket-Key用于防止非 WebSocket 客户端无意中或滥用请求 WebSocket 连接。
  • Sec-WebSocket-Version指定客户端希望使用的 WebSocket 协议版本

这些信息我们都不用手动处理, 浏览器的 WebSocket API 已经帮我们处理好了。我们只管简单的使用就好了。

GET ws://127.0.0.1:8081/ HTTP/1.1
Host: 127.0.0.1:8081
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
Upgrade: websocket
Origin: null
Sec-WebSocket-Version: 13
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Sec-WebSocket-Key: bdXy5LYyPmxVi9ISux//gQ==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits

当服务端收到客户端的 WebSocket 连接时,起始行会告诉浏览器是否支持这个协议。如果正常返回状态码: 例如 200,说明服务器忽略本次协议升级。如果服务端支持协议升级,响应报文起始行会返回 HTTP/1.1 101 Switching Protocols ,告诉浏览器支持协议升级。

  • Upgrade: 升级协议
  • Sec-WebSocket-Accept: 说明服务器愿意发起 WebSocket 连接。其包含在打开握手过程中来自服务器的响应消息中。它只会在响应标头中出现一次
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: 7nSh4Fi5hvy0cRMURV29MpkaZbQ=

总结

协议升级不仅仅用于 WebSocket,还可以将协议升级为 HTTP 2.0。这个机制是可选的。它并不能强制协议的更改(通常来说这一机制总是由客户端发起的)。如果它们支持新协议,实现甚至可以不利用 upgrade,在实践中,这种机制主要用于引导 WebSocket 连接。

WebSocket协议是一个基于HTTP的协议,它在单个TCP连接上进行全双工通信。WebSocket 主要功能是用来和服务端进行实时通信。如果想使用从0开始来实现WebSocket,你需要自己实现WebSocket协议,这需要深入理解WebSocket协议的工作原理,包括消息帧的解析、心跳机制、分片消息的传输等等

相关参考

RFC6455:websocket规范

规范:数据帧掩码细节

规范:数据帧格式

server-example

编写websocket服务器

对网络基础设施的攻击(数据掩码操作所要预防的事情)

What is Sec-WebSocket-Key for?

10.3. Attacks On Infrastructure (Masking)

Why are WebSockets masked?

How does websocket frame masking protect against cache poisoning?

What is the mask in a WebSocket frame?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值