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

时间:2017-02-21 01:30:57

标签: python django websocket channels

在JavaScript中,浏览器可以将子协议指定为WebSocket创建中的第二个参数:

socket=new WebSocket(url, subprotocol)

使用Chrome进行试验,可以将其作为标题中的Sec-WebSocket-Protocol元素正确发送到服务器。

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

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

给出错误

  

WebSocket连接到' xxx'失败:WebSocket握手期间出错:发送非空的Sec-WebSocket-Protocol'标题但未收到任何回复。

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

3 个答案:

答案 0 :(得分:2)

我遇到了同样的问题。 Websocket规范说,如果客户端要求子协议,那么服务器必须响应让客户知道它支持它。在我的情况下,子协议是“graphql-ws”

在石墨烯代码中挖掘之后,最终发现在设置中添加以下内容是一个简单的例子:

CHANNELS_WS_PROTOCOLS = ["graphql-ws"]

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

答案 1 :(得分:2)

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

my-protocol

答案 2 :(得分:0)

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

当您在消费者的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