如何修复无法使用Python和ASGI与WebSockets建立连接到Django Channels服务器的错误?

kqlmhetl  于 2023-06-06  发布在  Python
关注(0)|答案(1)|浏览(105)

Django通道和websockets:无法与服务器建立连接。

我正在尝试使用django channels,websockets和p5做一个实时绘图应用程序。

我唯一的问题是Firefox无法建立到服务器的连接,该服务器位于ws://XXX. XXX.XXX.XXX:8090/ws/room/1/。

我做了什么:

settings.py :

INSTALLED_APPS = [
    ...
    'channels',
]

ASGI_APPLICATION = 'DrawMatch.asgi.application'

CHANNEL_LAYERS = {
    'default': {
        "BACKEND": "channels.layers.InMemoryChannelLayer"
    }
}

asgi.py :

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'DrawMatch.settings')
django_asgi_app = get_asgi_application()

application = ProtocolTypeRouter({
    "http": django_asgi_app,
    "websocket": AllowedHostsOriginValidator(
        AuthMiddlewareStack(
            URLRouter(
                drawmatch_app.routing.websocket_urlpatterns
            )
        )
    ),
})

consumers.py :

class DrawConsumer(AsyncJsonWebsocketConsumer):
    room_code: str = None
    room_group_name: str = None

    async def connect(self):
        self.room_code = self.scope['url_route']['kwargs']['room_code']
        self.room_group_name = f'room_{self.room_code}'
        print(f"room_code: {self.room_code}")
        print(f"room_group_name: {self.room_group_name}")

        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )
        await self.accept()

    async def disconnect(self, close_code):
        await self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name
        )

    async def receive(self, text_data: str = None, _: Any = None) -> None:
        data = json.loads(text_data)
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'draw',
                'data': data
            }
        )

    async def send_message(self, res):
        await self.send(text_data=json.dumps({
            "payload": res
        }))

routing.py :

websocket_urlpatterns = [
    url(r'^ws/room/(?P<room_code>\w+)/$', DrawConsumer.as_asgi()),
]

views.py :

def room(request, room_code):
    context = {
        'room_code': room_code
    }
    return render(request, 'room.html', context)

urls.py :

urlpatterns = [
    path('', views.home),
    ...
    path('room/<room_code>/', views.room),
    path('predict', draw_guess.main),
]

房间:

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <title>DrawMatch - Room {{ room_code }}</title>
    <link rel="stylesheet" href="{% static 'styles/style.css' %}">
    <script src="{% static 'scripts/index.mjs' %}" type="module"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.min.js"></script>
    <script>
        const csrftoken = '{{ csrf_token }}';
        const room_code = {{ room_code }};
        const connectionString = `ws://${window.location.host}/ws/room/{{room_code}}/`;
        const gameSocket = new WebSocket(connectionString);
    </script>
</head>
<body>
    <h1>Room {{ room_code }}</h1>
    <div class="drawings-container"></div>
</body>
</html>

index.js:

const WIDTH = 500;
const HEIGHT = 500;
const STROKE_WEIGHT = 3;
const drawingsContainer = document.querySelector(".drawings-container");

console.log(gameSocket);

gameSocket.onmessage = (e) => {
    console.log(`Server: ${e.data}`)
    const data = JSON.parse(e.data);
    if (data.type === "draw") {
        const {
            canvas, x, y, px, py
        } = data.data;
        canvas.line(x, y, px, py);
    }
}

gameSocket.onopen = (e) => {
    console.log("Connected to websocket");
}

gameSocket.onclose = (e) => {
    console.log("Disconnected from websocket");
}

function setupCanvas(canvas, id) {
    console.log(connectionString);
    let timeout;
    let drawing = false;

    canvas.setup = () => {
        canvas.createCanvas(WIDTH, HEIGHT);
        canvas.strokeWeight(STROKE_WEIGHT);
        canvas.stroke("black");
        canvas.background("#FFFFFF");
        canvas.canvas.id = id;
        drawingsContainer.appendChild(canvas.canvas);
    }

    canvas.draw = () => {
        if (!drawing) return;
        canvas.line(canvas.mouseX, canvas.mouseY, canvas.pmouseX, canvas.pmouseY);

        if (timeout) return;
        timeout = setTimeout(async () => {
            const image = canvas.canvas.toDataURL();
            const response = await fetch("/predict", {
                method: "POST", body: JSON.stringify({
                    image
                }), headers: {
                    "X-CSRFToken": csrftoken, "Content-Type": "application/json"
                }
            })
            const data = await response.text();
            console.log(data);
            gameSocket.send(JSON.stringify({
                type: "draw", data: {
                    canvas: canvas.id, x: canvas.mouseX, y: canvas.mouseY, px: canvas.pmouseX, py: canvas.pmouseY
                }
            }));
            timeout = null;
        }, 200);
    }

    canvas.mousePressed = () => drawing = canvas.mouseX > 0 && canvas.mouseX <= WIDTH && canvas.mouseY > 0 && canvas.mouseY <= HEIGHT;

    canvas.mouseReleased = () => drawing = false
}

new p5(leftCanvas => {
    setupCanvas(leftCanvas, "leftCanvas");
})

new p5(rightCanvas => {
    setupCanvas(rightCanvas, "rightCanvas");
})
kiayqfof

kiayqfof1#

问题出现在routing.py:

websocket_urlpatterns = [
    url(r'^ws/room/(?P<room_code>\w+)/$', DrawConsumer.as_asgi()),
]

正确的版本是:

websocket_urlpatterns = [
    path('ws/room/<room_code>/', DrawConsumer.as_asgi()),
]

相关问题