部署Flask+Nginx+Gunicorn+React应用时WebSocket连接失败求助
问题描述
应用本身运行正常,但WebSocket无法建立连接,报错信息:
WebSocket connection to 'wss://localhost:8080/socket.io/?combat_id=elayn-1670267089069&EIO=4&transport=websocket' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
应用在本地及Heroku部署均正常,当前服务器使用Nginx 1.18.0监听8000端口,怀疑问题出在Nginx配置或IP地址设置上。
现有配置与代码
Nginx配置文件
server { listen 0.0.0.0:8000; listen [::]:8000; root /app/app/static/build; index index.html; location / { proxy_pass http://127.0.0.1:8080; proxy_redirect default; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; } location /socket.io/ { proxy_pass http://127.0.0.1:8080/socket.io; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_redirect default; proxy_set_header Host $host; } }
Flask后端代码
app.py
from app import app, socketio if __name__ == "__main__": socketio.run(app, debug=False, port="8080")
init.py
import os from dotenv import load_dotenv from flask import Flask, render_template, redirect, url_for, flash, request, abort from flask_bootstrap import Bootstrap from werkzeug.security import generate_password_hash, check_password_hash from flask_sqlalchemy import SQLAlchemy from sqlalchemy.orm import relationship from flask_login import UserMixin, login_user, LoginManager, login_required, current_user, \ logout_user from flask_cors import CORS from flask_socketio import SocketIO, emit # -------------------- INIT APP -------------------- load_dotenv() app = Flask(__name__, template_folder="./") app.debug = True app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY") app.config['CORS_HEADERS'] = 'Content-Type' socketio = SocketIO(app, cors_allowed_origins="http://127.0.0.1:8080/", logger=True, engineio_logger=True) # CONNECT TO DB app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("DATABASE_URL") app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False # LOGIN MANAGER db = SQLAlchemy(app) login_manager = LoginManager(app) bootstrap = Bootstrap(app) from app import models, forms, routes, handlers from app.auth import forms, routes # db.create_all() # db.session.commit()
应用启动命令
/srv/venv/bin/gunicorn -b 127.0.0.1:8080 --worker-class eventlet -w 1 app:app
React前端Socket.io代码
socket = io("localhost:8080/", { transports: ["websocket"], cors: { origin: "*", }, query: `combat_id=${combatInfo.id}`, });
已尝试的解决方法
- 修改React及配置中的IP地址(如localhost:8080、127.0.0.1:8080等)
- 移除Socket.io URL中的端口
- 调整Nginx配置参数
- 将eventlet替换为gevent
解决方案
核心问题分析
报错显示前端尝试直接连接localhost:8080,但生产环境中前端运行在用户浏览器,localhost指向用户本地而非部署服务器,导致连接被拒绝。同时Nginx的WebSocket配置存在细节缺失,后端CORS设置也不符合生产环境需求。
具体修复步骤
修正前端Socket.io连接地址
前端应连接Nginx监听的8000端口,使用相对路径自动适配当前页面的域名和端口,避免硬编码:socket = io("/", { transports: ["websocket"], cors: { origin: window.location.origin, }, query: `combat_id=${combatInfo.id}`, });完善Nginx的WebSocket代理配置
添加超时设置,并修正proxy_pass路径的拼接问题:server { listen 0.0.0.0:8000; listen [::]:8000; root /app/app/static/build; index index.html; location / { proxy_pass http://127.0.0.1:8080/; proxy_redirect default; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location /socket.io/ { proxy_pass http://127.0.0.1:8080/socket.io/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $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; # 添加WebSocket超时设置 proxy_connect_timeout 7d; proxy_send_timeout 7d; proxy_read_timeout 7d; } }更新后端CORS及SocketIO配置
生产环境中cors_allowed_origins应设置为服务器公网域名/IP,或允许前端实际访问的地址:# __init__.py中修改SocketIO初始化 socketio = SocketIO(app, cors_allowed_origins="*", logger=True, engineio_logger=True) # 或更严格指定前端地址,如"https://your-domain.com"同时确保Flask-CORS配置生效:
CORS(app)验证后端启动状态
确认eventlet已正确安装:pip install eventlet通过
curl http://127.0.0.1:8080验证后端服务是否在127.0.0.1:8080正常运行。
内容的提问来源于stack exchange,提问作者Elanaris

