Django 频道。如何使用子协议响应 WebSocket 打开请求?

Django Channels. How to respond to a WebSocket open request with a subprotocol?

在 JavaScript 中,浏览器可以指定 sub-protocol 作为 WebSocket 创建中的第二个参数:

socket=new WebSocket(url, subprotocol)

使用 Chrome 进行试验,这会作为 header.

中的 Sec-WebSocket-Protocol 元素正确发送到服务器

使用Django通道,一个简单的消费者

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

报错

WebSocket connection to 'xxx' failed: Error during WebSocket handshake: Sent non-empty 'Sec-WebSocket-Protocol' header but no response was received.

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

我遇到了同样的问题。 Websocket 规范说,如果客户端请求子协议,则服务器必须响应让客户端知道它支持它。在我的例子中,子协议是 "graphql-ws"

在深入研究石墨烯代码后,最终发现将以下内容添加到设置中是一个简单的案例:

CHANNELS_WS_PROTOCOLS = ["graphql-ws"]

因此,只需将协议列表替换为您想要支持的任何协议即可。当然,一旦你完成了这个,你实际上需要在服务器上实现子协议。

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

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

如果有人像我一样偶然发现这个问题,我是这样解决的:

当您在消费者的连接方法上调用 self.accept() 时,您需要添加您在前端使用的 websocket 协议(在我的例子中是令牌)作为子协议参数:

这是我在前端创建 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 频道 2.4.0 Django 3.1.2