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

huangapple go评论123阅读模式
英文:

How can I fix the error of not being able to establish a connection to a Django Channels server with WebSockets using Python and ASGI?

问题

Django channels & websockets:无法建立与服务器的连接。

我正在尝试使用Django Channels、Websockets和p5创建实时绘图应用程序。

我唯一遇到的问题是:Firefox无法建立与服务器的连接,连接地址为ws://XXX.XXX.XXX.XXX:8090/ws/room/1/。

我所做的:

settings.py:

  1. INSTALLED_APPS = [
  2. ...
  3. 'channels',
  4. ]
  5. ASGI_APPLICATION = 'DrawMatch.asgi.application'
  6. CHANNEL_LAYERS = {
  7. 'default': {
  8. "BACKEND": "channels.layers.InMemoryChannelLayer"
  9. }
  10. }

asgi.py:

  1. os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'DrawMatch.settings')
  2. django_asgi_app = get_asgi_application()
  3. application = ProtocolTypeRouter({
  4. "http": django_asgi_app,
  5. "websocket": AllowedHostsOriginValidator(
  6. AuthMiddlewareStack(
  7. URLRouter(
  8. drawmatch_app.routing.websocket_urlpatterns
  9. )
  10. )
  11. ),
  12. })

consumers.py:

  1. class DrawConsumer(AsyncJsonWebsocketConsumer):
  2. room_code: str = None
  3. room_group_name: str = None
  4. async def connect(self):
  5. self.room_code = self.scope['url_route']['kwargs']['room_code']
  6. self.room_group_name = f'room_{self.room_code}'
  7. print(f"room_code: {self.room_code}")
  8. print(f"room_group_name: {self.room_group_name}")
  9. await self.channel_layer.group_add(
  10. self.room_group_name,
  11. self.channel_name
  12. )
  13. await self.accept()
  14. async def disconnect(self, close_code):
  15. await self.channel_layer.group_discard(
  16. self.room_group_name,
  17. self.channel_name
  18. )
  19. async def receive(self, text_data: str = None, _: Any = None) -> None:
  20. data = json.loads(text_data)
  21. await self.channel_layer.group_send(
  22. self.room_group_name,
  23. {
  24. 'type': 'draw',
  25. 'data': data
  26. }
  27. )
  28. async def send_message(self, res):
  29. await self.send(text_data=json.dumps({
  30. "payload": res
  31. }))

routing.py:

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

views.py:

  1. def room(request, room_code):
  2. context = {
  3. 'room_code': room_code
  4. }
  5. return render(request, 'room.html', context)

urls.py:

  1. urlpatterns = [
  2. path('', views.home),
  3. ...
  4. path('room/<room_code>/', views.room),
  5. path('predict', draw_guess.main),
  6. ]

room.html:

  1. {% load static %}
  2. <!DOCTYPE html>
  3. <html lang="en">
  4. <head>
  5. <title>DrawMatch - Room {{ room_code }}</title>
  6. <link rel="stylesheet" href="{% static 'styles/style.css' %}">
  7. <script src="{% static 'scripts/index.mjs' %}" type="module"></script>
  8. <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.min.js"></script>
  9. <script>
  10. const csrftoken = '{{ csrf_token }}';
  11. const room_code = {{ room_code }};
  12. const connectionString = `ws://${window.location.host}/ws/room/{{room_code}}/`;
  13. const gameSocket = new WebSocket(connectionString);
  14. </script>
  15. </head>
  16. <body>
  17. <h1>Room {{ room_code }}</h1>
  18. <div class="drawings-container"></div>
  19. </body>
  20. </html>

index.js:

  1. const WIDTH = 500;
  2. const HEIGHT = 500;
  3. const STROKE_WEIGHT = 3;
  4. const drawingsContainer = document.querySelector(".drawings-container");
  5. console.log(gameSocket);
  6. gameSocket.onmessage = (e) => {
  7. console.log(`Server: ${e.data}`)
  8. const data = JSON.parse(e.data);
  9. if (data.type === "draw") {
  10. const {
  11. canvas, x, y, px, py
  12. } = data.data;
  13. canvas.line(x, y, px, py);
  14. }
  15. }
  16. gameSocket.onopen = (e) => {
  17. console.log("Connected to websocket");
  18. }
  19. gameSocket.onclose = (e) => {
  20. console.log("Disconnected from websocket");
  21. }
  22. function setupCanvas(canvas, id) {
  23. console.log(connectionString);
  24. let timeout;
  25. let drawing = false;
  26. canvas.setup = () => {
  27. canvas.createCanvas(WIDTH, HEIGHT);
  28. canvas.strokeWeight(STROKE_WEIGHT);
  29. canvas.stroke("black");
  30. canvas.background("#FFFFFF");
  31. canvas.canvas.id = id;
  32. drawingsContainer.appendChild(canvas.canvas);
  33. }
  34. canvas.draw = () => {
  35. if (!drawing) return;
  36. canvas.line(canvas.mouseX, canvas.mouseY, canvas.pmouseX, canvas.pmouseY);
  37. if (timeout) return;
  38. timeout = setTimeout(async () => {
  39. const image = canvas.canvas.toDataURL();
  40. const response = await fetch("/predict", {
  41. method: "POST", body: JSON.stringify({
  42. image
  43. }), headers: {
  44. "X-CSRFToken": csrftoken, "Content-Type": "application/json"
  45. }
  46. })
  47. const data = await response.text();
  48. console.log(data);
  49. gameSocket.send(JSON.stringify({
  50. type: "draw", data: {
  51. canvas: canvas.id, x: canvas.mouseX, y: canvas.mouseY, px: canvas.pmouseX, py: canvas.pmouseY
  52. }
  53. }));
  54. timeout = null;
  55. }, 200);
  56. }
  57. canvas.mousePressed = () => drawing = canvas.mouseX > 0 && canvas.mouseX <= WIDTH && canvas.mouseY > 0 && canvas.mouseY <= HEIGHT;
  58. canvas.mouseReleased = () => drawing = false
  59. }
  60. new p5(leftCanvas => {
  61. setupCanvas(leftCanvas, "leftCanvas");
  62. })
  63. new p5(rightCanvas => {
  64. setupCanvas(rightCanvas, "rightCanvas");
  65. })
英文:

Django channels & websockets : can’t establish a connection to the server.

I am trying to do a real-time drawing app using django channels, websockets & p5.

The only problem I've got is : Firefox can’t establish a connection to the server at ws://XXX.XXX.XXX.XXX:8090/ws/room/1/.

What I've done :

settings.py :

  1. INSTALLED_APPS = [
  2. ...
  3. &#39;channels&#39;,
  4. ]
  5. ASGI_APPLICATION = &#39;DrawMatch.asgi.application&#39;
  6. CHANNEL_LAYERS = {
  7. &#39;default&#39;: {
  8. &quot;BACKEND&quot;: &quot;channels.layers.InMemoryChannelLayer&quot;
  9. }
  10. }

asgi.py :

  1. os.environ.setdefault(&#39;DJANGO_SETTINGS_MODULE&#39;, &#39;DrawMatch.settings&#39;)
  2. django_asgi_app = get_asgi_application()
  3. application = ProtocolTypeRouter({
  4. &quot;http&quot;: django_asgi_app,
  5. &quot;websocket&quot;: AllowedHostsOriginValidator(
  6. AuthMiddlewareStack(
  7. URLRouter(
  8. drawmatch_app.routing.websocket_urlpatterns
  9. )
  10. )
  11. ),
  12. })

consumers.py :

  1. class DrawConsumer(AsyncJsonWebsocketConsumer):
  2. room_code: str = None
  3. room_group_name: str = None
  4. async def connect(self):
  5. self.room_code = self.scope[&#39;url_route&#39;][&#39;kwargs&#39;][&#39;room_code&#39;]
  6. self.room_group_name = f&#39;room_{self.room_code}&#39;
  7. print(f&quot;room_code: {self.room_code}&quot;)
  8. print(f&quot;room_group_name: {self.room_group_name}&quot;)
  9. await self.channel_layer.group_add(
  10. self.room_group_name,
  11. self.channel_name
  12. )
  13. await self.accept()
  14. async def disconnect(self, close_code):
  15. await self.channel_layer.group_discard(
  16. self.room_group_name,
  17. self.channel_name
  18. )
  19. async def receive(self, text_data: str = None, _: Any = None) -&gt; None:
  20. data = json.loads(text_data)
  21. await self.channel_layer.group_send(
  22. self.room_group_name,
  23. {
  24. &#39;type&#39;: &#39;draw&#39;,
  25. &#39;data&#39;: data
  26. }
  27. )
  28. async def send_message(self, res):
  29. await self.send(text_data=json.dumps({
  30. &quot;payload&quot;: res
  31. }))

routing.py :

  1. websocket_urlpatterns = [
  2. url(r&#39;^ws/room/(?P&lt;room_code&gt;\w+)/$&#39;, DrawConsumer.as_asgi()),
  3. ]

views.py :

  1. def room(request, room_code):
  2. context = {
  3. &#39;room_code&#39;: room_code
  4. }
  5. return render(request, &#39;room.html&#39;, context)

urls.py :

  1. urlpatterns = [
  2. path(&#39;&#39;, views.home),
  3. ...
  4. path(&#39;room/&lt;room_code&gt;/&#39;, views.room),
  5. path(&#39;predict&#39;, draw_guess.main),
  6. ]

room.html :

  1. {% load static %}
  2. &lt;!DOCTYPE html&gt;
  3. &lt;html lang=&quot;en&quot;&gt;
  4. &lt;head&gt;
  5. &lt;title&gt;DrawMatch - Room {{ room_code }}&lt;/title&gt;
  6. &lt;link rel=&quot;stylesheet&quot; href=&quot;{% static &#39;styles/style.css&#39; %}&quot;&gt;
  7. &lt;script src=&quot;{% static &#39;scripts/index.mjs&#39; %}&quot; type=&quot;module&quot;&gt;&lt;/script&gt;
  8. &lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.min.js&quot;&gt;&lt;/script&gt;
  9. &lt;script&gt;
  10. const csrftoken = &#39;{{ csrf_token }}&#39;;
  11. const room_code = {{ room_code }};
  12. const connectionString = `ws://${window.location.host}/ws/room/{{room_code}}/`;
  13. const gameSocket = new WebSocket(connectionString);
  14. &lt;/script&gt;
  15. &lt;/head&gt;
  16. &lt;body&gt;
  17. &lt;h1&gt;Room {{ room_code }}&lt;/h1&gt;
  18. &lt;div class=&quot;drawings-container&quot;&gt;&lt;/div&gt;
  19. &lt;/body&gt;
  20. &lt;/html&gt;

index.js :

  1. const WIDTH = 500;
  2. const HEIGHT = 500;
  3. const STROKE_WEIGHT = 3;
  4. const drawingsContainer = document.querySelector(&quot;.drawings-container&quot;);
  5. console.log(gameSocket);
  6. gameSocket.onmessage = (e) =&gt; {
  7. console.log(`Server: ${e.data}`)
  8. const data = JSON.parse(e.data);
  9. if (data.type === &quot;draw&quot;) {
  10. const {
  11. canvas, x, y, px, py
  12. } = data.data;
  13. canvas.line(x, y, px, py);
  14. }
  15. }
  16. gameSocket.onopen = (e) =&gt; {
  17. console.log(&quot;Connected to websocket&quot;);
  18. }
  19. gameSocket.onclose = (e) =&gt; {
  20. console.log(&quot;Disconnected from websocket&quot;);
  21. }
  22. function setupCanvas(canvas, id) {
  23. console.log(connectionString);
  24. let timeout;
  25. let drawing = false;
  26. canvas.setup = () =&gt; {
  27. canvas.createCanvas(WIDTH, HEIGHT);
  28. canvas.strokeWeight(STROKE_WEIGHT);
  29. canvas.stroke(&quot;black&quot;);
  30. canvas.background(&quot;#FFFFFF&quot;);
  31. canvas.canvas.id = id;
  32. drawingsContainer.appendChild(canvas.canvas);
  33. }
  34. canvas.draw = () =&gt; {
  35. if (!drawing) return;
  36. canvas.line(canvas.mouseX, canvas.mouseY, canvas.pmouseX, canvas.pmouseY);
  37. if (timeout) return;
  38. timeout = setTimeout(async () =&gt; {
  39. const image = canvas.canvas.toDataURL();
  40. const response = await fetch(&quot;/predict&quot;, {
  41. method: &quot;POST&quot;, body: JSON.stringify({
  42. image
  43. }), headers: {
  44. &quot;X-CSRFToken&quot;: csrftoken, &quot;Content-Type&quot;: &quot;application/json&quot;
  45. }
  46. })
  47. const data = await response.text();
  48. console.log(data);
  49. gameSocket.send(JSON.stringify({
  50. type: &quot;draw&quot;, data: {
  51. canvas: canvas.id, x: canvas.mouseX, y: canvas.mouseY, px: canvas.pmouseX, py: canvas.pmouseY
  52. }
  53. }));
  54. timeout = null;
  55. }, 200);
  56. }
  57. canvas.mousePressed = () =&gt; drawing = canvas.mouseX &gt; 0 &amp;&amp; canvas.mouseX &lt;= WIDTH &amp;&amp; canvas.mouseY &gt; 0 &amp;&amp; canvas.mouseY &lt;= HEIGHT;
  58. canvas.mouseReleased = () =&gt; drawing = false
  59. }
  60. new p5(leftCanvas =&gt; {
  61. setupCanvas(leftCanvas, &quot;leftCanvas&quot;);
  62. })
  63. new p5(rightCanvas =&gt; {
  64. setupCanvas(rightCanvas, &quot;rightCanvas&quot;);
  65. })

答案1

得分: 1

问题出在routing.py文件中:

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

正确的版本是:

  1. websocket_urlpatterns = [
  2. path('ws/room/<room_code>/', DrawConsumer.as_asgi()),
  3. ]
英文:

The problem was in routing.py :

  1. websocket_urlpatterns = [
  2. url(r&#39;^ws/room/(?P&lt;room_code&gt;\w+)/$&#39;, DrawConsumer.as_asgi()),
  3. ]

the correct version is :

  1. websocket_urlpatterns = [
  2. path(&#39;ws/room/&lt;room_code&gt;/&#39;, DrawConsumer.as_asgi()),
  3. ]

huangapple
  • 本文由 发表于 2023年5月30日 01:30:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/76359287.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定