Nginx и Flask-socketio Websockets: Жив, но не обмен сообщениями?
У меня были небольшие проблемы с тем, чтобы Nginx хорошо играл с библиотекой Python Flask-socketio (которая основана на gevent). В настоящее время, поскольку мы активно развиваемся, я пытаюсь заставить Nginx просто работать в качестве прокси. Для отправки страниц я могу заставить это работать, либо непосредственно запустив приложение колба-сокетио, либо запустив Gunicorn. Одна загвоздка: обмен сообщениями через веб-сокет не работает. Страницы успешно размещены и отображаются. Однако когда я пытаюсь использовать веб-сокеты, они не работают. Они достаточно живы, чтобы веб-сокет думал, что он подключен, но они не будут отправлять сообщение. Если я удалю прокси Nginx, они будут работать. Firefox выдает мне эту ошибку, когда я пытаюсь отправить сообщение:
Firefox не может установить соединение с сервером по адресу ws:///socket.io/1/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;
}
}
}
Я сделал конфигурационный файл как смесь общего примера и конкретного веб-сокета, но попытка возиться с ним не решила проблему. Кроме того, я использую вызов werkzeug Proxy_Fix на моем Flask app.wsgi_app, когда использую его в режиме wsgi. Я пробовал с этим и без него, но безрезультатно. Если у кого-то есть понимание, у меня будут все уши / глаза.
1 ответ
Мне удалось это исправить. Проблемы не были характерны для колбы-сокета, но они были характерны для Ubuntu, NginX и gevent-socketio. Были представлены две важные проблемы:
- Ubuntu 12.04 имеет действительно древнюю версию nginx (1.1.19 против 1.6.x для стабильных версий). Зачем? Кто знает. Что мы знаем, так это то, что эта версия не поддерживает веб-сокеты каким-либо полезным способом, поскольку 1.3.13 является самой ранней версией, которую вы должны использовать.
- По умолчанию gevent-socketio ожидает, что ваши сокеты находятся в каталоге /socket.io . Вы можете обновить все HTTP-соединение, но у меня возникли некоторые проблемы с его настройкой (особенно после того, как я добавил SSL).
- Я исправил #1, но, поигравшись с ним, я удалил nginx и установил apt-get... версию nginx по умолчанию в Ubuntu. Тогда я был загадочно смущен тем, почему все работает даже хуже, чем раньше. Многие файлы.conf отважно погибли в этой битве.
При попытке отладки веб-сокетов в этой конфигурации я бы порекомендовал следующие шаги:
- Проверьте вашу версию nginx через 'nginx -v'. Если это что-то меньше, чем 1.4, обновите его.
- Проверьте настройки nginx.conf. Вы должны убедиться, что подключение обновляется.
- Убедитесь, что IP-адрес и порт вашего сервера совпадают с обратным прокси-сервером nginx.conf.
- Убедитесь, что ваш клиент (например, socketio.js) подключается к правильному расположению и порту с правильным протоколом.
- Проверьте ваши заблокированные порты. Я был на EC2, поэтому вы должны вручную открыть 80 (HTTP) и 443 (SSL/HTTPS).
Просто проверив все эти вещи, есть вынос.
Обновление до последней стабильной версии nginx в Ubuntu ( полная ссылка) может быть выполнено:
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, Node.js с SSL). Файл конфигурации для nginx 1.6 с flask-socketio (который включает gevent-socketio) и SSL:
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.