WebSocket 连接到 'wss:// 失败:WebSocket 握手期间出错:通道上出现意外响应代码:404

WebSocket 连接到 'wss:// 失败:WebSocket 握手期间出错:通道上出现意外响应代码:404

我在 django 上使用 WebSockets 通道时遇到此错误生产

WebSocket connection to 'wss://domain.me/ws/orders/confirm_all/' failed: Error during WebSocket handshake: Unexpected response code: 404

而在 localhost 上没有问题(使用 runserver 命令)

路由.py:

from django.conf.urls import url

from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from management.consumers import ConfirmAllOrdersConsumer

application = ProtocolTypeRouter({
    'websocket': AuthMiddlewareStack(
        URLRouter([
            url(r'ws/orders/confirm_all/$', ConfirmAllOrdersConsumer),

        ])
    ),
})

js:

const ws_scheme = window.location.protocol === "https:" ? "wss" : "ws";

const ordersSocket = new WebSocket(
    ws_scheme + '://'
    + window.location.host
    + '/ws/orders/confirm_all/'
);

消费者.py:

import json
from channels.generic.websocket import WebsocketConsumer
from orders.models import Orders
from time import sleep


class ConfirmAllOrdersConsumer(WebsocketConsumer):

    def connect(self):
        self.accept()

    def disconnect(self, code):
        self.disconnect(code)

    def receive(self, text_data=None, bytes_data=None):
        text_data_json = json.loads(text_data)
        action = text_data_json['action']

        if action == 'confirm_all':
            revision_orders = Orders.objects.filter(status__exact='revision')
            for idx, order in enumerate(revision_orders):
                print(idx)
                order.status = 'confirmed'
                order.save()
                sleep(0.33)

                self.send(json.dumps({
                    'total_orders': revision_orders.count(),
                    'new_val': idx + 1
                }))


它在 localhost 上通过 http/ws 工作,但在生产上通过 https/wss 不工作


我猜它来自 apache 配置,而不是脚本代码,所以这是我的 apache2 配置:

Apache2website.conf

<VirtualHost *:80>
        # The ServerName directive sets the request scheme, hostname and port that
        # the server uses to identify itself. This is used when creating
        # redirection URLs. In the context of virtual hosts, the ServerName
        # specifies what hostname must appear in the request's Host: header to
        # match this virtual host. For the default virtual host (this file) this
        # value is not decisive as it is used as a last resort host regardless.
        # However, you must set it for any further virtual host explicitly.

        ServerName example.com
        ServerAlias www.example.com

        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/html

        # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
        # error, crit, alert, emerg.
        # It is also possible to configure the loglevel for particular
        # modules, e.g.
        #LogLevel info ssl:warn

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

        # For most configuration files from conf-available/, which are
        # enabled or disabled at a global level, it is possible to
        # include a line for only one particular virtual host. For example the
        # following line enables the CGI configuration for this host only
        # after it has been globally disabled with "a2disconf".
        #Include conf-available/serve-cgi-bin.conf

RewriteEngine on
RewriteCond %{SERVER_NAME} =www.example.com [OR]
RewriteCond %{SERVER_NAME} =example.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

Apache2website-le-ssl.conf

<IfModule mod_ssl.c>
<VirtualHost *:443>
        # The ServerName directive sets the request scheme, hostname and port that
        # the server uses to identify itself. This is used when creating
        # redirection URLs. In the context of virtual hosts, the ServerName
        # specifies what hostname must appear in the request's Host: header to
        # match this virtual host. For the default virtual host (this file) this
        # value is not decisive as it is used as a last resort host regardless.
        # However, you must set it for any further virtual host explicitly.

        ServerName example.com
        ServerAlias www.example.com

        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/html


    RewriteEngine On
    RewriteCond %{HTTP_HOST} ^www\. [NC,OR]
    RewriteCond %{HTTPS} !on
    RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
    RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L,NE]

        #RewriteEngine On
        #RewriteCond %{HTTP_HOST} ^www.example.com [NC]
        #RewriteRule ^/(.*)$ https://example.com/$1 [L,R=301]

        # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
        # error, crit, alert, emerg.
        # It is also possible to configure the loglevel for particular
        # modules, e.g.
        #LogLevel info ssl:warn

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

        # For most configuration files from conf-available/, which are
        # enabled or disabled at a global level, it is possible to
        # include a line for only one particular virtual host. For example the
        # following line enables the CGI configuration for this host only
        # after it has been globally disabled with "a2disconf".
        #Include conf-available/serve-cgi-bin.conf

    Alias /static /home/user/website/static
    <Directory /home/user/website/static>
        Require all granted
    </Directory>

        Alias /media /home/user/website/media
        <Directory /home/user/website/media>
                Require all granted
        </Directory>

    <Directory /home/user/website/my_project/>
        <Files wsgi.py>
            Require all granted
        </Files>
    </Directory>

    WSGIScriptAlias / /home/user/website/my_project/wsgi.py
    WSGIDaemonProcess website_app python-path=/home/user/website python-home=/home/user/website/venv
    WSGIProcessGroup website_app
    
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
</VirtualHost>
</IfModule>

有什么想法吗?谢谢。

相关内容