Настройте nginx, uwsgi с колбой и колбу-сокето - PullRequest
1 голос
/ 09 мая 2019

Я написал приложение Flask, которое использует flask-socketio . Я использую колбу с портом 8000 и клиентское приложение отдельно с портом 3000 (реакции-webpack). Он работает безупречно в режиме разработки (веб-сервер предоставляется в колбе). Однако при попытке запустить с помощью UWSGI у меня возникают проблемы. Эти проблемы и конфигурации будут подробно описаны ниже.

wsgi.py (остается неизменным)

from cloud_app import app, sock
if __name__ == "__main__":
    sock.run(app,host='0.0.0.0', debug=True, port=8000)

__ init __. Py (остается постоянной)

from flask import Flask
from flask_socketio import SocketIO
import secrets

app = Flask(__name__, static_url_path='/static')
app.secret_key = secrets.secret_key
sock = SocketIO(app)

from cloud_app import routes

rout.py (остается неизменным с очевидным удалением реальной логики)

...
from flask_cors import CORS
cors = CORS(app, resources={r"/*": {"origins": "*"}}, headers=['Content-Type'], expose_headers=['Access-Control-Allow-Origin'], supports_credentials=True)

@app.route('/example')
def example():
    return 'example'

@sock.on('connect', namespace='/example')
def handle_example_connect():
    sock.emit('example', 'Connected!\nAwaiting commands...\n', namespace='/example')
...

Первая конфигурация

взято из документации для flask-socketio и uwsgi переведено в INI-файл

[uwsgi]
module = wsgi:app

master = true
processes = 5
buffer-size=32768
http-websockets = true

http = :8000
gevent = 1000

Конфигурация nginx здесь не нужна, поскольку веб-пакет обслуживает это, а ini-файл настроен на прямой ответ на запросы http ' http =: port '

КОНСОЛЬ: иногда печатается, что он подключен 'Подключен! Ожидание команд ... 'из события connect в rout.py , однако оно также выдаст следующие ошибки

POST http://localhost:8000/socket.io/?EIO=3&transport=polling&t=MgTjSL-&sid=5bf4758a09034805b1213fec92620e39 400 (BAD REQUEST)
GET http://localhost:8000/socket.io/?EIO=3&transport=polling&t=MgTjSMG&sid=5bf4758a09034805b1213fec92620e39 400 (BAD REQUEST)
websocket.js:112 WebSocket connection to 'ws://localhost:8000/socket.io/?EIO=3&transport=websocket&sid=5bf4758a09034805b1213fec92620e39' failed: Error during WebSocket handshake: Unexpected response code: 400

Выход процесса UWSGI:

...
[pid: 9402|app: 0|req: 16/33] 127.0.0.1 () {44 vars in 1316 bytes} [Thu May  9 13:55:41 2019] POST /socket.io/?EIO=3&transport=polling&t=MgTl93y&sid=b208e874c0e64330bdde35ae1773b4e0 => generated 2 bytes in 0 msecs (HTTP/1.1 200) 3 headers in 137 bytes (3 switches on core 996)
[pid: 9402|app: 0|req: 17/34] 127.0.0.1 () {40 vars in 1255 bytes} [Thu May  9 13:55:41 2019] GET /socket.io/?EIO=3&transport=polling&t=MgTl94Q&sid=b208e874c0e64330bdde35ae1773b4e0 => generated 12 bytes in 0 msecs (HTTP/1.1 200) 3 headers in 151 bytes (3 switches on core 996)
...
[pid: 9402|app: 0|req: 27/48] 127.0.0.1 () {44 vars in 1316 bytes} [Thu May  9 13:56:57 2019] POST /socket.io/?EIO=3&transport=polling&t=MgTlRbG&sid=5c4c38f18f6b47798978440edd181512 => generated 2 bytes in 0 msecs (HTTP/1.1 200) 3 headers in 137 bytes (3 switches on core 998)
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 2309, in __call__
    return self.wsgi_app(environ, start_response)
  File "/usr/local/lib/python2.7/dist-packages/flask_socketio/__init__.py", line 43, in __call__
    start_response)
  File "/usr/local/lib/python2.7/dist-packages/engineio/middleware.py", line 47, in __call__
    return self.engineio_app.handle_request(environ, start_response)
  File "/usr/local/lib/python2.7/dist-packages/socketio/server.py", line 360, in handle_request
    return self.eio.handle_request(environ, start_response)
  File "/usr/local/lib/python2.7/dist-packages/engineio/server.py", line 322, in handle_request
    start_response(r['status'], r['headers'] + cors_headers)
IOError: headers already sent

...

Вторая конфигурация

Взято из этого вопроса . INI-файл

[uwsgi]
module = wsgi:app

master = true
processes = 5
buffer-size=32768
http-websockets = true

socket = example_app.sock
chmod-socket = 666

vaccum = true
die-on-term = true

nginx server

server {
    listen 8000;
    location /{
        include uwsgi_params;
        uwsgi_pass unix:/path/to/app/example_app.sock;
    }

    location /socket.io {
        #include proxy_params;
        proxy_http_version 1.1;
        #proxy_buffering off;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_pass http://unix:/path/to/app/example_app.sock;
    }
}

Закомментированные опции были ранее оставлены без комментариев

Ошибки

Консоль

polling-xhr.js:263 GET http://localhost:8000/socket.io/?EIO=3&transport=polling&t=MgTotN9 502 (Bad Gateway)
Access to XMLHttpRequest at 'http://localhost:8000/socket.io/?EIO=3&transport=polling&t=MgTotN9' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

журнал ошибок nginx (/ var / log / nginx / error_log)

2019/05/09 14:16:35 [error] 11338#0: *1 upstream prematurely closed connection while reading response header from upstream, client: 127.0.0.1, server: , request: "GET /socket.io/?EIO=3&transport=polling&t=MgTpw36 HTTP/1.1", upstream: "http://unix:/path/to/app/example_app.sock:/socket.io/?EIO=3&transport=polling&t=MgTpw36", host: "localhost:8000", referrer: "http://localhost:3000/home"

Обратите внимание, что в обоих примерах http-запросы (обслуживаемые приложением) работают нормально, только вызовы сокетов дают проблемы.

1 Ответ

1 голос
/ 10 мая 2019

flask_socketio оборачивает приложение и использует разные протоколы в зависимости от того, что доступно и как оно вызывается.Он может использовать как HTTP-опрос, так и собственные веб-сокеты, два разных метода с использованием двух разных протоколов.

Если eventlet или gevent используется исключительно, тогда используется опрос, то есть запросы HTTP.

Если UWSGI используется, используются собственные веб-сокеты (ws).

Если gevent или eventlet используется вместе с uwsgi , собственным веб-сокетомиспользуется реализация из uwsgi .

В моем случае я использовал socket.io на клиенте, который использует http-опрос, поэтому, когда я пытался использовать uwsgi,сервер ожидал собственное подключение к веб-сокету и не имел ничего, что обрабатывало бы HTTP-опрос.

Поэтому, чтобы решить мою проблему, я протестировал следующие решения

  • Удалите UWSGI, поскольку flask_socketio +eventlet или gevent создает готовую производственную конфигурацию ( docs )
  • Использование собственных WS и UWSGI (наличие eventlet или gevent не имеет значения, поскольку реализация UWSGI используется независимо)
...