-
Notifications
You must be signed in to change notification settings - Fork 39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
如何理解mqtt用到的101交换协议 #250
Comments
101交换协议HTTP的101交换协议意味着client向server发送的消息中包含了Upgrade请求头,server会根据client发送的这个请求头切换协议。 server会在response中添加一个Upgrade响应头,来指示server切换到的协议。 用一句话来说就是:client通过在请求头中添加Upgrade告诉server切换协议,server在响应头中添加upgrade说明切换后的协议。 再简单一点就是:客户端告诉服务端去切换协议。 General
Request Headers
Response Headers
其中这些请求头是什么意思呢?Connection,Sec-WebSocket-Extensions,Sec-WebSocket-Key,Sec-WebSocket-Protocol,Sec-WebSocket-Version等等。 看了下面的协议升级机制就明白了。 |
协议升级机制HTTP1.1版本的协议有一个特殊的机制:升级一个已经建立的连接为另外一个协议,一般是通过Upgrade头来实现。 这个机制是可选的,它不能强制协议改变。虽然实现支持新协议,但是也可以选择不升级。在实际应用中,通常这个机制用于引导WebSocket进行连接。 注意,HTTP2.0版本明确禁止使用这个机制。只能用于HTTP1.1。 升级HTTP/1.1连接client可以使用Upgrade头去邀请服务器去切换为协议列表中的某一项,按照降序。 因为Upgrade是一个逐跳头,因此它需要一个Connection头。
其他的头一般是依赖请求协议的;例如,WebSocket升级允许额外的头去配置WebSocket连接,并在打开时就有一定的安全性。 如果服务器决定去升级连接,分为升级成功和升级失败两种情况:
服务器发送完101状态码之后,它可以立即开始使用新协议,并且进行与其他协议的handshake。一旦连接建立完成,连接就变为双向管道,初始化升级的请求可以再协议之上初始化。 协议升级机制的常规用法Upgrade这个头会用在哪些场景呢?而且与WebSocket连接有关的请求头都有哪些呢?
升级为WebSocket连接最常见的升级HTTP连接的场景,就是使用WebSockets的场景,通常是通过升级HTTP或者HTTPS连接的方式来实现。如果你使用WebSocket API去开启一个连接,或者任何WebSockets的库,大多数或者说所有的事情都已经为你做好了。 例如:建立一个WebSocket连接非常简单,只需要这样既可: webSocket = new WebSocket("ws://destination.server.ext", "optionalProtocol")
如果你想自己手动建立一个WebSocket连接的话,你需要自己去处理握手过程。在创建完HTTP/1.1会话之后,你需要在请求上添加Upgrade和Connection这两个请求头。
与WebSocket连接有关的请求头下面这些请求头是WebSocket升级过程中包含的请求头。与Upgrade和Connection头不同,下面这些请求头 Sec-WebSocket-Extensions声明一个或者多个协议级的WebSocket扩展区告诉服务器使用。在一个请求里使用一个或者多个Sec-WebSocket-Extension头是可以的;放在一起用分号隔开也可以。
extensions需要用分号分开。需要从插件列表里选择。 例如: 我们上面例子中的permessage-deflate也在其中。
Sec-WebSocket-Key向服务端提供客户端有权升级为WebSocket的信息。这个头可用于不安全的HTTP想要升级时,为了提供某种程度的保护,防止滥用。key的值使用在WebSocket规范中定义的算法生成,所以这并不保证安全性。 这个key是为了放置非WebSocket的客户端无意中进行websocket连接或者滥用。 这个头会自动被使用它的客户端添加,不能被XMLHttpRequest.setRequestHeader() 添加
基于这个key,服务器会在响应的Sec-WebSocket-Accept头中加一个基于这个key的计算数据。 Sec-WebSocket-Protocol这个头会声明一个或者多个你想要使用的WebSocket协议。
subprotocols包括以下这些协议:https://www.iana.org/assignments/websocket/websocket.xml#subprotocol-name 上面示例中的mqtt也在其中: Sec-WebSocket-Version作为请求头:
服务器与客户端通信的WebSocket协议版本:https://www.iana.org/assignments/websocket/websocket.xml#version-number 作为响应头:
Sec-WebSocket-Accept服务器与客户端建立握手过程中的响应头。至多出现一次:
如果有Sec-WebSocket-Key,将字符串“ 258EAFA5-E914-47DA-95CA-C5AB0DC85B11”连接到该字符串,并且取SHA-1的20位 hash值。最后进行base64编码。 在我们的例子中:
通过Sec-WebSocket-Key生成Sec-WebSocket-Accept的编码过程如下: const SecWebSocketKey = "xxx"
const helper = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
const result = SecWebSocketKey + helper
const crypto = require('crypto')
const shasum = crypto.createHash('sha1')
shasum.update(result)
const SecWebSocketAccept = shasum.digest('base64');
console.log(SecWebSocketAccept) // fNs9ByuvC+rD75+tj2GMQAzbJms= 在线demo:https://www.jdoodle.com/ia/e3G 既然key到accept的算法已经很明晰了,那么可以通过accept反向求解出key吗? 密码强哈希函数有两个特点:其中一个很重要的特点就是不可逆。不可逆性意味着原始数据无法从其散列中重建,所以不能通过accept反向求解出key。 |
使用过mqtt的同学都知道,mqtt连接时,在Network面板中的status是101。
那么101(Switching Protocols)到底是什么意思呢?
这篇文章将带你理解101交换协议是什么,以及101交换协议运用的协议升级机制。
The text was updated successfully, but these errors were encountered: