Nginx / Daphne / WebSocket连接失败:WebSocket握手期间出错:意外的响应代码:404

时间:2019-12-23 10:11:59

标签: django docker nginx amazon-ec2 websocket

所以我在上使用 Ubuntu 18.04.3 LTS,Django 3.0.0,Python 3.6,Nginx,Daphne,docker,Channels AWS EC2实例。 我从Channels开始了一个类似教程的项目。我正在尝试通过wss协议建立websocket连接。当主机为http且websocket连接为ws协议时,一切工作正常。但是如果主机是https并且websocket连接是wss协议,则会出错。 错误如下。

  

(索引):16 WebSocket与'wss:// mydomain / ws / chat / 1 /'的连接失败:WebSocket握手期间出错:意外的响应代码:404

我正在运行 Daphne 的django aspi应用程序。使用 Channels-redis 作为渠道层。并由 docker 运行redis。这是我运行应用服务器的方式:

@font-face {
    font-family: 'yourfont Novum Light';
    src: local('yourfont Novum Light') url("https://cns.xx.com/ux/site/1.1/fonts/yourfont-novum/yourfont-Novum-Light.eot");

font-weight: 400;
font-style: normal

我在Django项目的settings.py中的channel_layers。

daphne -u /home/ubuntu/virtualenvs/src/werewolves/werewolves.sock werewolves.asgi:application
sudo docker run --restart unless-stopped -p 6379:6379 -d redis:2.8

这是我的Nginx设置:

#settings.py
...
CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            "hosts": ["127.0.0.1",6379],
            "symmetric_encryption_keys": ["mykey"],
            },
    }
}
...

这是我的routing.py。

upstream websocket {
server unix:/home/ubuntu/virtualenvs/src/werewolves/werewolves.sock;
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
server_name mydomain;

location = /favicon.ico { access_log off; log_not_found off; }
location ^~ /static/ {
    autoindex on;
    alias /home/ubuntu/virtualenvs/static/static-only/; #STATIC_ROOT
}
# SSL settings
ssl on;
listen 443 ssl http2;
listen [::]:443 ssl http2 default_server;
ssl_certificate /etc/letsencrypt/live/mydomain/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mydomain/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/mydomain/fullchain.pem;
ssl_session_timeout 10m;
ssl_session cache shared:SSL:1m;

location / {
# proxy setting for django using wsgi
include proxy_params;
#proxy_pass 0.0.0.0:8000;
proxy_pass websocket;
# CORS config. settings for using AWS S3 serving static file
set $origin '*'; #origin url;
if ($request_method = 'OPTIONS') {
    add_header 'Access-Control-Allow-Origin' $origin;
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
    #
    # Custom headers and headers various browsers *should* be OK
    # with but aren't
    #
    add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Co$
    #
    # Tell client that this pre-flight info is valid for 20 days
    #
    add_header 'Access-Control-Max-Age' 1728000;
    add_header 'Content-Type' 'text/plain; charset=utf-8';
    add_header 'Content-Length' 0;
     return 204;
 }
 if ($request_method = 'POST') {
    add_header 'Access-Control-Allow-Origin' $origin;
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
    add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Co$
    add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
 }
 if ($request_method = 'GET') {
    add_header 'Access-Control-Allow-Origin' $origin;
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
    add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Co$
    add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
 }
}

location ^~ /ws/ {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

proxy_set_header X-Frame-Options SAMEORIGIN;
proxy_pass http://websocket;
}
location ~* \.(js|css)$ {
expires -1;
 }
}

这是我运行应用程序的方式。

此JS websocket命令可用于URL:http://mydomain/chat/1/

# mysite/routing.py
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
import gameroom.routing

application = ProtocolTypeRouter({
    # (http->django views is added by default)
    'websocket': AuthMiddlewareStack(
        URLRouter(
            gameroom.routing.websocket_urlpatterns
        )
    ),
})

# chat/routing.py
from django.urls import re_path
from . import consumers

websocket_urlpatterns = [
    re_path(r'^ws/chat/(?P<room_name>\w+)/$', consumers.ChatConsumer),
]

问题是此JS websocket命令不适用于URL:https://mydomain/chat/1/

var chatSocket = new WebSocket('ws://' + window.location.host + '/ws/chat/1/');

来自浏览器的错误消息是:

  

(索引):16 WebSocket与'wss:// mydomain / ws / chat / 1 /'的连接失败:WebSocket握手期间出错:意外的响应代码:404

达芙妮返回以下消息。

var chatSocket = new WebSocket('wss://' + window.location.host + '/ws/chat/1/');

如何修改Nginx设置? 顺便说一句,我没有适用于我的AWS EC2实例的ELB(负载均衡器)。

1 个答案:

答案 0 :(得分:0)

nginx示例:

upstream channels-backend {
    server 0.0.0.0:8099;
}


server {
  listen 80;
  server_name {domain};
  return 301 https://$host$request_uri;

}


server {

  proxy_connect_timeout 220s;
  proxy_read_timeout 220s;

  client_max_body_size 4G;
  listen 443 ssl;
  server_name {domain};
  ssl_certificate {cert-path};
  ssl_certificate_key {cert-path};

  access_log /{log-path};
  error_log /{log-path};


  location /sockets {
     try_files $uri @proxy_to_app;
  }

  location @proxy_to_app {
        proxy_pass http://channels-backend;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Host $server_name;
  }

}

达芬妮

daphne -b 0.0.0.0 -p 8099 {your-app}.asgi:application