我在 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>
有什么想法吗?谢谢。