Nginx and Flask-socketio Websockets: Alive but not Messaging?
让Nginx与Python Flask-socketio库(基于gevent)很好地协作时,我一直遇到一些麻烦。当前,由于我们正在积极开发中,因此我试图让Nginx充当代理。对于发送页面,我可以通过直接运行flask-socketio应用程序或通过运行gunicorn使其工作。一个障碍:websocket消息传递似乎无效。页面已成功托管并显示。但是,当我尝试使用websocket时,它们不起作用。他们还活着,以至于Websocket认为它已连接,但是他们不会发送消息。如果我删除了Nginx代理,它们就会起作用。当我尝试发送消息时,Firefox给了我这个错误:
Firefox can't establish a connection to the server at ws:///socket.io/1/websocket/.
网址是服务器所在的位置,唯一ID只是一堆随机数字。它似乎足以保持连接状态(例如,客户端认为已连接),但无法通过网络套接字发送消息。我不得不认为问题与代理的某些部分有关,但是在调试问题的根源上却遇到了很大的麻烦(部分原因是这是我对Flask-socketIO和nginx的第一次尝试)。我用于nginx的配置文件是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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。存在两个重要问题:
如果尝试在此配置中调试websocket,则建议执行以下步骤:
刚刚检查了所有这些内容之后,便有了外卖服务。
可以通过以下方法将Ubuntu升级到最新的稳定Nginx版本(完整参考):
1 2 3 4 5 | 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教程,Gevent-socketio,带有SSL的Node.js)。使用flask-socketio(包装gevent-socketio)和SSL的nginx 1.6的配置文件是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | 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使用正确的端口很容易。这足以解决上述问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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这样的客户端,连接应该很容易。例如:
1 2 3 4 5 6 | <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/0.9.16/socket.io.min.js"> <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") |
打开端口实际上实际上是服务器故障或超级用户问题,因为打开端口在很大程度上取决于防火墙。对于Amazon EC2,请参阅此处。
如果尝试所有这些方法均无效,请哭泣。然后返回到列表的顶部。因为您可能只是不小心重新安装了较旧的nginx版本。