如何修复“WebSocket 握手期间的错误:意外响应代码:400”?

问题描述

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

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

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

我的应用程序已启动并正在运行,但 Socket 未连接。所以我在客户端看到的错误是: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. 为 socket.io 调整我的 Nginx 代码(多种配置)

什么有效:

  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",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 使用同步工作类来处理请求,但它可以配置为使用 gevent。