簡體   English   中英

使用flask和flask-socketio配置nginx、uwsgi

[英]Configure nginx, uwsgi with flask and flask-socketio

我編寫了一個使用flask-socketio的 Flask 應用程序。 我在端口 8000 上運行燒瓶應用程序,在端口 3000 (react-webpack) 上分別運行客戶端應用程序。 它在開發模式下完美運行(Flask 中提供的 Web 服務器)。 但是,當嘗試使用 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

routes.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 配置,因為 webpack 提供了這個,ini 文件被配置為直接響應 http 請求 ' http=:port '

控制台:這有時會打印它正在連接“已連接! 等待命令...'來自routes.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 {
    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 請求(由應用程序服務的請求)都可以正常工作,只有套接字調用會出現問題。

flask_socketio包裝應用程序並根據可用的內容和調用方式使用不同的協議。 它可以同時使用 HTTP 輪詢和本機 Websocket,這兩種不同的方法使用兩種不同的協議。

如果獨占使用eventletgevent ,則使用輪詢,即http請求。

如果使用UWSGI ,則使用原生 websocket (ws)。

如果geventeventletuwsgi一起使用,則使用來自uwsgi的本機 websocket 實現。

在我的例子中,我在客戶端上使用了socket.io ,它使用了 http 輪詢,因此當我嘗試使用 uwsgi 時,服務器期望一個本地 websocket 連接並且沒有任何處理 http 輪詢的東西。

所以為了解決我的問題,我測試了以下解決方案

  • 刪除 UWSGI,因為 flask_socketio + eventlet 或 gevent 產生了生產就緒配置( 文檔
  • 使用本機 WS 和 UWSGI(有 eventlet 或 gevent 無關緊要,因為無論如何都使用 UWSGI 的實現)

請注意,根據 socketio 文檔,在使用多個 uwsgi 實例(這是其默認模式)時,您必須通過在創建 SocketIO 對象時指定message_queue選項來配置緩存服務器,例如 Redis。 如果您使用默認緩存,則客戶端將連接,但在與服務器通信時您將經常收到400 錯誤 確認這是您的問題的一種方法是將 uwsgi 配置為僅運行一個進程,例如processes=1 如果這消除了問題,那么很可能是您的消息隊列。 有關如何配置它的信息可以在以下位置找到: https ://flask-socketio.readthedocs.io/en/latest/deployment.html#uwsgi-web-server

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM