如何修复 "Error during WebSocket handshake: Unexpected response code: 400"?

How do I fix the "Error during WebSocket handshake: Unexpected response code: 400"?

我正在使用 Nginx + Gunicorn + Flask_SocketIo + Docker.

我是 运行 一个 Nginx 容器和一个 EC2 实例上的 python/alpine 容器。

我使用 flask_SocketIo 每 5 秒向客户端页面发送一次信息而无需重新加载页面。

我的应用程序已启动,但 运行 但套接字未连接。所以我在客户端看到的错误是:WebSocket 握手期间出错:意外的响应代码:400

我从服务器端的 Nginx 得到的消息是:

**69.xxx.xxx.xxx - - [20/Dec/2020:21:06:54 +0000] "GET /socket.io/?EIO=3&transport=websocket HTTP/1.1" 400 23 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.x.xxxx.xx Safari/537.36" "-"**

我的应用程序做的是:

  1. 客户端访问 http://domain.com/project ->
  2. 已建立套接字连接,服务器上的帖子“已连接”->
  3. 单击按钮后 ->
  4. 服务器不断发送信息,发布在HTML页面

我试过的:

  1. 从 uWSGI 切换到 Gunciorn 服务器
  2. 调整我的 Nginx 代码 socket.io(多个配置)

什么有效:

  1. 我的 python 个脚本
  2. 输入域名后网页加载
  3. 在没有 Nginx 的情况下进行本地测试时,我的代码似乎运行良好。

这是我的 Nginx 配置:

upstream nameOfApp {
    server app:8080;
}
server {
    listen 80;
    server_name 54.xxx.xxx.xx;
    server_name www.domain;
    location / {
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_pass http://nameOfApp;
        }
    location /socket.io/ {
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_pass http://nameOfApp;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection "upgrade";
        proxy_http_version 1.1;
        }
    }

这是我的docker-compose

version: "3.7"

services:

    app:
        build:
            context: ./App
            dockerfile: Dockerfile
        command: gunicorn mainApp.run:app --bind 0.0.0.0:8080
        container_name: app
        restart: always
        environment:
            - APP_NAME=CordLte
        expose:
            - 8080
    nginx:
        build: ./Nginx
        container_name: nginx
        restart: always
        ports:
            - '80:80'
        depends_on:
            - app

值得一提的是,我在客户端关闭了轮询

var socket = io({transports: ['websocket'], upgrade: false});

更新 Miguel 的推荐:

我打开了 socket.io 记录器

app      | 627211f5e8984f13a467f051bc560a29: Sending packet MESSAGE data 0

app      | 627211f5e8984f13a467f051bc560a29: Received request to upgrade to websocket

nginx    | 69.xxx.xxx.xxx - - [21/Dec/2020:11:41:44 +0000] "GET /socket.io/?EIO=3&transport=websocket HTTP/1.1" 400 23 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.x.xxxx.xx Safari/537.36" "-"

app      | 129d66e4d815482cb0251c913e6cb004: Sending packet OPEN data {'sid': '129d66e4d815482cb0251c913e6cb004', 'upgrades': [], 'pingTimeout': 60000, 'pingInterval': 25000}

app      | 129d66e4d815482cb0251c913e6cb004: Sending packet MESSAGE data 0

app      | 129d66e4d815482cb0251c913e6cb004: Received request to upgrade to websocket

nginx    | 69.xxx.xxx.xxx - - [21/Dec/2020:11:41:50 +0000] "GET /socket.io/?EIO=3&transport=websocket HTTP/1.1" 400 23 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.x.xxxx.xx Safari/537.36" "-"

这是点击按钮后记录器的结果:

app      | 1c0df226c9b14e8c8da8afe9bd1601c7: Sending packet MESSAGE data 2["message",{"data":["678",0]}]

app      | 7bda92d2ea9a41c5abd22f4576d6a075: Sending packet MESSAGE data 2["message",{"data":["678",0]}]

app      | 1c0df226c9b14e8c8da8afe9bd1601c7: Client is gone, closing socket

app      | 1c0df226c9b14e8c8da8afe9bd1601c7: Client is gone, closing socket

app      | 7bda92d2ea9a41c5abd22f4576d6a075: Sending packet MESSAGE data 2["message",{"data":["680",0]}]

如果还有什么我可以澄清的,请告诉我

几天后...我发现了我的问题。

我需要在 docker-compose 命令上添加 -k gevent。我需要添加 gevent 来处理我的事件循环。 Gunicorn 使用同步 worker class 来处理请求,但它可以配置为使用 gevent。