Django Channels. 如何使用子协议响应WebSocket的打开请求?

6
在JavaScript中,浏览器可以在WebSocket创建时指定子协议作为第二个参数:
socket=new WebSocket(url, subprotocol)

在使用Chrome进行实验时,这个元素会正确地作为头部的Sec-WebSocket-Protocol元素发送到服务器。

通过使用Django channels,可以创建一个简单的消费者。

def ws_add(message):
    message.reply_channel.send({"accept": True,})

出现错误

WebSocket连接到 'xxx' 失败:在 WebSocket 握手期间发送了非空的 'Sec-WebSocket-Protocol' 标头,但没有收到响应。

Django channels 的 ws_add 函数中接受该连接请求的正确方法是什么?

3个回答

8

websocket.accept消息中,您必须指定要使用的子协议。例如,如果您继承于channels.generic.websocket.WebsocketConsumer(也适用于SyncConsumer),并且使用 my-protocol 作为 Sec-WebSocket-Protocol

class MyProtocolConsumer(WebsocketConsumer):
    def websocket_connect(self, message):
        self.base_send({"type": "websocket.accept", "subprotocol": "my-protocol"})

4
我遇到了相同的问题。Websocket规范指出,如果客户端请求子协议,则服务器必须响应,以让客户端知道它支持该协议。在我的情况下,子协议是 "graphql-ws"。
在探索 graphene 代码后,最终发现只需将以下内容添加到设置中即可解决问题:
CHANNELS_WS_PROTOCOLS = ["graphql-ws"]
因此,只需用您想支持的协议列表替换原有列表即可。当然,一旦完成此操作,您实际上需要在服务器上实现子协议。

3
"CHANNELS_WS_PROTOCOLS在Channels 2.0及以上版本中不再受支持。" - Amr Ellafy
我应该添加哪些设置? - Raul H

0
如果有人像我一样遇到这个问题,请看我是怎么解决的:
当你在consumer的connect方法中调用self.accept()时,你需要将你在前端使用的websocket协议(例如Token)作为子协议参数添加进去,如下所示:
这是我在前端创建websocket连接的方式:
const websocket = new WebSocket('ws://127.0.0.1:8000/ws/', ['Token', 'user_secret_token'])

这是我的consumers.py文件的样子:

class MyConsumer(JsonWebsocketConsumer):
    def connect(self):
        self.room_group_name = 'example_room'

        # Join room group
        async_to_sync(self.channel_layer.group_add)(self.room_group_name, self.channel_name)

        # incorrect
        # self.accept()

        # correct
        self.accept('Token')

Django Channels 2.4.0 Django 3.1.2

Django通道2.4.0 Django 3.1.2


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接