我在让 Nginx 与 Python Flask-socketio 库(基于 gevent)很好地配合时遇到了一些麻烦。目前,由于我们正在积极开发,我正在尝试让 Nginx 充当代理。对于发送页面,我可以通过直接运行flask-socketio应用程序或通过gunicorn运行来使其工作。一个问题是:websocket 消息传递似乎不起作用。页面已成功托管并显示。但是,当我尝试使用网络套接字时,它们不起作用。它们足够活跃,以至于 websocket 认为它们已连接,但它们不会发送消息。如果我删除 Nginx 代理,它们就可以工作。当我尝试发送消息时,Firefox 出现此错误:
Firefox 无法与位于 ws:///socket.io/1/websocket/ 的服务器建立连接。
其中网址是服务器所在的位置,唯一 ID 只是一堆随机数字。它似乎已经做了足够的事情来保持连接有效(例如,客户端认为它已连接),但无法通过 websocket 发送消息。我必须认为这个问题与代理的某些部分有关,但是我在调试问题可能是什么时遇到了很大的麻烦(部分原因是这是我第一次使用 Flask-socketIO 和 nginx)。我用于 nginx 的配置文件是:
user <user name>; ## This is set to the user name for the remote SSH session
worker_processes 5;
events {
worker_connections 1024; ## Default: 1024
}
http {
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] $status '
'"$request" $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
sendfile on;
server_names_hash_bucket_size 128; # this seems to be required for some vhosts
server {
listen 80;
server_name _;
location / {
proxy_pass http://localhost:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
}
}
我将配置文件作为一般示例和 websocket 特定示例的混合体,但尝试摆弄它并没有解决问题。另外,当我在 wsgi 模式下使用 Flask app.wsgi_app 时,我正在使用 werkzeug Proxy_Fix 调用。我已经尝试过使用和不使用它,但都无济于事。如果有人有一些见解,我会洗耳恭听。
我设法解决了这个问题。这些问题并不是 Flask-socketio 特有的,而是 Ubuntu、NginX 和 gevent-socketio 特有的。存在两个重要问题:
- Ubuntu 12.04 有一个真正古老的 nginx 版本(稳定版本为 1.1.19 与 1.6.x)。为什么?谁知道。我们所知道的是,这个版本不以任何有用的方式支持 websockets,因为 1.3.13 是关于最早的 https://github.com/LearnBoost/socket.io/wiki/Nginx-and-Socket.io你应该使用。
- 默认情况下,gevent-socketio 希望您的套接字位于 /socket.io 位置。您可以升级整个 HTTP 连接,但我在使其正常工作时遇到了一些麻烦(尤其是在我将 SSL 加入其中之后)。
- 我修复了 #1,但在摆弄它时,我通过 nginx 进行了清除,并安装了 apt-get...Ubuntu 上 nginx 的默认版本。然后,我对为什么事情比以前更糟糕感到困惑。许多.conf 文件在这场战斗中勇敢地献出了生命。
如果尝试在此配置中调试 Websocket,我建议执行以下步骤:
- 通过“nginx -v”检查您的 nginx 版本。如果低于 1.4,请升级。
- 检查您的 nginx.conf 设置。您需要确保连接升级。
- 检查您的服务器 IP 和端口是否与您的 nginx.conf 反向代理匹配。
- 检查您的客户端(即套接字 io.js)是否使用正确的协议连接到正确的位置和端口。
- 检查您被阻止的端口。我在 EC2 上,所以你必须手动打开 80 (HTTP) 和 443 (SSL/HTTPS)。
刚刚检查了所有这些事情后,有一些要点。
-
在 Ubuntu 上升级到最新的稳定 nginx 版本(full ref https://www.digitalocean.com/community/articles/how-to-install-the-latest-version-of-nginx-on-ubuntu-12-10)可以通过以下方式完成:
sudo apt-get install python-software-properties
sudo apt-get install software-properties-common
sudo add-apt-repository ppa:nginx/stable
sudo apt-get update
sudo apt-get install nginx
在 Windows 等系统中,您可以使用安装人员 http://nginx.org/en/download.html并且不太可能得到不好的版本。
-
许多配置文件可能会令人困惑,因为 nginx 在 2013 年左右正式添加了套接字,使得早期的解决方法配置变得过时。现有的配置文件往往不会涵盖 nginx、gevent-socketio 和 SSL 的所有基础,而是将它们分开(Nginx 教程 https://chrislea.com/2013/02/23/proxying-websockets-with-nginx/, Gevent-socketio http://gevent-socketio.readthedocs.org/en/latest/server_integration.html, Node.js 与 SSL https://www.exratione.com/2013/06/websockets-over-ssl-with-nodejs-and-nginx/)。带有flask-socketio(包装gevent-socketio)和SSL的nginx 1.6的配置文件是:
user <user account, probably optional>;
worker_processes 2;
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
access_log /var/log/nginx/access.log;
sendfile on;
# tcp_nopush on;
keepalive_timeout 3;
# tcp_nodelay on;
# gzip on;
client_max_body_size 20m;
index index.html;
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
# Listen on 80 and 443
listen 80 default;
listen 443 ssl; (only needed if you want SSL/HTTPS)
server_name <your server name here, optional unless you use SSL>;
# SSL Certificate (only needed if you want SSL/HTTPS)
ssl_certificate <file location for your unified .crt file>;
ssl_certificate_key <file location for your .key file>;
# Optional: Redirect all non-SSL traffic to SSL. (if you want ONLY SSL/HTTPS)
# if ($ssl_protocol = "") {
# rewrite ^ https://$host$request_uri? permanent;
# }
# Split off basic traffic to backends
location / {
proxy_pass http://localhost:8081; # 127.0.0.1 is preferred, actually.
proxy_redirect off;
}
location /socket.io {
proxy_pass http://127.0.0.1:8081/socket.io; # 127.0.0.1 is preferred, actually.
proxy_redirect off;
proxy_buffering off; # Optional
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
}
-
检查 Flask-socketio 是否使用正确的端口很容易。这足以与上述内容一起使用:
from flask import Flask, render_template, session, request, abort
import flask.ext.socketio
FLASK_CORE_APP = Flask(__name__)
FLASK_CORE_APP.config['SECRET_KEY'] = '12345' # Luggage combination
SOCKET_IO_CORE = flask.ext.socketio.SocketIO(FLASK_CORE_APP)
@FLASK_CORE_APP.route('/')
def index():
return render_template('index.html')
@SOCKET_IO_CORE.on('message')
def receive_message(message):
return "Echo: %s"%(message,)
SOCKET_IO_CORE.run(FLASK_CORE_APP, host=127.0.0.1, port=8081)
-
对于像 socketio.js 这样的客户端,连接应该很容易。例如:
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/0.9.16/socket.io.min.js"></script>
<script type="text/javascript">
var url = window.location.protocol + document.domain + ':' + location.port,
socket = io.connect(url);
socket.on('message', alert);
io.emit("message", "Test")
</script>
开放端口实际上更多的是服务器故障 https://serverfault.com/search?q=unblock%20port or a 超级用户 https://superuser.com/search?q=unblock%20port问题,因为这在很大程度上取决于您的防火墙。对于 Amazon EC2,请参阅here http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-network-security.html.
如果尝试所有这些都不起作用,那就哭吧。然后返回到列表顶部。因为您可能只是不小心重新安装了旧版本的 nginx。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)