我目前正在生产环境中使用
Django Channels
部署应用程序。
目标应用程序基于官方
django channel
文档中的示例应用程序。
https://channels.readthedocs.io/en/latest/tutorial/index.html
我已经确认它在不使用
SSL
的生产环境中运行良好,但在使用SSL
更改设置时效果不佳。
执行
chatSocket.send
函数时,开发者工具控制台出现如下错误。
未捕获的 DOMException:无法在 Websocket 上执行发送:仍处于 CONNECTING 状态
所以我参考下面的文章修改了代码,但是
chatSocket.readyState
并没有从0开始变化。
未捕获 InvalidStateError:无法在“WebSocket”上执行“发送”:仍处于 CONNECTING 状态
如何解决此错误?
以下是代码:
room.html(javascript)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Chat Room</title>
</head>
<body>
<textarea id="chat-log" cols="100" rows="20"></textarea><br>
<input id="chat-message-input" type="text" size="100"><br>
<input id="chat-message-submit" type="button" value="Send">
{{ room_name|json_script:"room-name" }}
<script>
const roomName = JSON.parse(document.getElementById('room-name').textContent);
const ws_scheme = window.location.protocol == "https:" ? "wss" : "ws";
const daphne_port = window.location.protocol == "https:" ? ":8001/" : "/";
const url = ws_scheme + '://' + window.location.host + daphne_port + 'ws/chat/' + roomName + '/';
const chatSocket = new WebSocket(url);
chatSocket.onmessage = function (e) {
const data = JSON.parse(e.data);
document.querySelector('#chat-log').value += (data.message + '\n');
};
chatSocket.onclose = function (e) {
console.error('Chat socket closed unexpectedly');
};
document.querySelector('#chat-message-input').focus();
document.querySelector('#chat-message-input').onkeyup = function (e) {
if (e.keyCode === 13) { // enter, return
document.querySelector('#chat-message-submit').click();
}
};
function waitForConnection(callback, interval) {
console.log('state:', chatSocket.readyState)
if (chatSocket.readyState === 1) {
callback();
} else {
const that = this;
// optional: implement backoff for interval here
setTimeout(function () {
that.waitForConnection(callback, interval);
}, interval);
}
};
document.querySelector('#chat-message-submit').onclick = function (e) {
const messageInputDom = document.querySelector('#chat-message-input');
const message = messageInputDom.value;
waitForConnection(function () {
chatSocket.send(JSON.stringify({
'message': message
}));
}, 1000
)
messageInputDom.value = '';
};
</script>
</body>
</html>
达芙妮服务
[Unit]
Description=WebSocket Daphne Service
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/home/ubuntu/chat_test
ExecStart=/home/ubuntu/chat_test/venv/bin/python /home/ubuntu/chat_test/venv/bin/daphne -e ssl:8001:privateKey=/etc/letsencrypt/live/sample.com/privkey.pem:certKey=/etc/letsencrypt/live/sample.com/fullchain.pem chat_test.asgi:application
Restart=on-failure
[Install]
WantedBy=multi-user.target
nginx
server {
listen 80;
listen [::]:80;
server_name sample.com;
return 301 https://$host$request_uri;
}
server {
listen 80;
listen 443 ssl;
server_name www.sample.com;
ssl_certificate /etc/letsencrypt/live/sample.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/sample.com/privkey.pem;
return 301 https://sample.com$request_uri;
}
server {
listen 443 ssl default_server;
server_name sample.com;
ssl_certificate /etc/letsencrypt/live/sample.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/sample.com/privkey.pem;
location =/fabicon.ico {access_log off; log_not_found off;}
location /static{
alias /usr/share/nginx/html/static;
}
location /media{
alias /usr/share/nginx/html/media;
}
location /{
include proxy_params;
proxy_pass http://unix:/home/ubuntu/chat_test/chat_test.sock;
}
location /ws/ {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_redirect off;
proxy_pass http://127.0.0.1:8001;
}
}
更新:
我更改了nginx文件,但仍然有同样的错误。
# location /ws/ {
# proxy_http_version 1.1;
# proxy_set_header Upgrade $http_upgrade;
# proxy_set_header Connection "upgrade";
# proxy_redirect off;
# proxy_pass http://127.0.0.1:8001;
#
# }
↓
location /ws/ {
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-Forwarded-Host $server_name;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Url-Scheme $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_redirect off;
proxy_pass http://127.0.0.1:8001;
}
ubuntu:20.40
蟒蛇:3.8.0
Django:4.2
频道:4.0.0
达芙妮:4.1.0
nginx:1.18.0
据我所知,这与你的
room.html
中的 javascript 有关,经过我自己的一些实验,我相信你可以摆脱这个 daphne_port
常量。
const url = ws_scheme + '://' + window.location.host + '/ws/chat/' + roomName + '/';
只有在删除它之后,我才可以在本地和通过 https/wss 在线工作。
发生的事情是,仅当服务器使用 https 运行时,
daphne_port
被设置为 :8001/
,这将使 url
等于 https://example.com:8001/ws/chat/room/
,这(可能)是不需要的。
并且由于
window.location.host
包括本地运行时的端口号(daphne_port
为空),因此一切正常。