我一直在让Nginx很好地使用Python Flask-socketio库(基于gevent)时遇到了一些麻烦。 目前,由于我们正在积极开发,我正试图让Nginx仅作为代理工作。 对于发送页面,我可以通过直接运行 flask-socketio 应用程序或通过 gunicorn 来使其工作。 一个障碍:websocket消息传递似乎不起作用。 页面已成功托管并显示。 但是,当我尝试使用 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模式下使用它时,我正在使用werkzeug Proxy_Fix调用我的烧瓶app.wsgi_app。 但是,我已经尝试过有和没有它,但无济于事。 如果有人有见解,我会全是耳朵/眼睛。
我设法解决了这个问题。 这些问题不是特定于flask-socketio的,但它们特定于Ubuntu,NginX和gevent-socketio。 存在两个重要问题:
- Ubuntu 12.04 有一个真正古老的 nginx 版本(稳定版本为 1.1.19 vs 1.6.x)。 为什么? 谁知道呢。 我们所知道的是,这个版本不以任何有用的方式支持 websockets,因为 1.3.13 是您应该使用的最早版本。
- 默认情况下,gevent-socketio 希望您的套接字位于位置/socket.io 。 您可以升级整个HTTP连接,但是我在使其正常工作时遇到了一些麻烦(尤其是在我将SSL放入混合之后)。 我
- 修复了#1,但在摆弄它时,我被nginx清除并安装了apt-get...Ubuntu 上 nginx 的默认版本。 然后,我神秘地困惑为什么事情比以前更糟。 许多.conf文件在这场战斗中英勇地失去了生命。
如果尝试在此配置中调试 websocket,我建议执行以下步骤:
- 通过"nginx -v"检查您的nginx版本。 如果低于 1.4,请升级它。
- 检查您的nginx.conf设置。 您需要确保连接升级。
- 检查您的服务器 IP 和端口是否与您的 nginx.conf 反向代理匹配。
- 检查您的客户端(例如socketio.js)是否使用正确的协议连接到正确的位置和端口。
- 检查被阻止的端口。 我在EC2上,所以你必须手动打开80(HTTP)和443(SSL/HTTPS)。
刚刚检查了所有这些东西,有外卖。
-
升级到 Ubuntu 上最新的稳定 nginx 版本(完整参考)可以通过以下方式完成:
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这样的系统中,您可以使用安装程序,并且不太可能获得错误版本。
-
许多配置文件可能会令人困惑,因为nginx在2013年左右正式添加了套接字,使得早期的解决方法配置过时了。 现有的配置文件并不倾向于涵盖nginx,gevent-socketio和SSL的所有基础,而是将它们分开(Nginx Tutorial,Gevent-socketio,Node.js与SSL)。 带有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>
-
打开端口实际上更像是服务器故障或超级用户问题,因为它在很大程度上取决于您的防火墙。 对于 Amazon EC2,请参阅此处。
-
如果尝试所有这些都不起作用,请哭泣。 然后返回到列表顶部。 因为您可能只是不小心重新安装了旧版本的nginx。