You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flask-SocketIO WebSocket连接失败及移动端事件接收问题求助

WebSocket首次连接失败(Flask-SocketIO + Nginx反向代理)

问题现象

  • JS客户端首次向Flask-SocketIO服务器emit事件时,出现错误:WebSocket connection to 'ws://(server ip)/socket.io/?EIO=4&transport=websocket&sid=52ViP_GqPGSr4DkqAAAN' failed,后续emit可正常运行
  • 移动端接收事件存在异常
  • 本地运行无此问题,服务器配置了Nginx反向代理

客户端代码

function formsubmitted(){
    var name = document.getElementById("startexampleInputEmail1").value
    var pin = document.getElementById("startexampleInputGamePin").value
    var predictions = document.getElementById("startexampleInputPredictions").value
    var joinmsg = document.getElementById("startexampleInputJoinMsg").value

    socket.emit("AccountCreation",[socket.id,name,pin,predictions,joinmsg])
}

服务器代码

@socketio.on("AccountCreation")
def handle_new_acc(data):
    sid = data[0]
    name = data[1]
    pin = data[2]
    predictions = data[3]
    joinmsg = data[4]
    canCreateAcc = True
    gameExists = False
    for user in User.query.all():
        if user.name == name:
            canCreateAcc = False
            emit("UsernameTaken",to=sid)
            return
    for game in Game.query.all():
        if game.pin == pin:
            gameExists = True

    if gameExists == False:
        emit("GameNotFound",to=sid)


    if gameExists == True and canCreateAcc == True:
        usertoadd = User(name,pin,predictions,joinmsg,1,"0 seconds","0 seconds",0,"")
        db.session.add(usertoadd)
        db.session.commit()
        game = Game.query.filter_by(pin=pin).first()
        player_list = json.loads(game.players)
        player_list.append(name)
        game.players = json.dumps(player_list)
        db.session.commit()
        emit("AccountReady",[name,pin,predictions,joinmsg],to=sid)

排查与解决方案

1. 修复Nginx反向代理配置

Nginx默认未开启WebSocket协议升级支持,需在代理配置的location块中添加以下指令:

location /socket.io/ {
    proxy_pass http://localhost:5000;  # 替换为你的Flask服务地址和端口
    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;
    proxy_http_version 1.1;
    proxy_cache_bypass $http_upgrade;
}

配置完成后重启Nginx,确保HTTP请求能正确升级为WebSocket连接。

2. 优化客户端连接时机

首次emit失败大概率是因为Socket连接尚未完全建立就发送事件,需确保连接就绪后再执行emit:

function formsubmitted(){
    // 检查连接状态
    if (!socket.connected) {
        console.log("连接未就绪,稍候重试");
        return;
    }
    var name = document.getElementById("startexampleInputEmail1").value
    var pin = document.getElementById("startexampleInputGamePin").value
    var predictions = document.getElementById("startexampleInputPredictions").value
    var joinmsg = document.getElementById("startexampleInputJoinMsg").value

    socket.emit("AccountCreation",[socket.id,name,pin,predictions,joinmsg])
}

更稳妥的方式是将emit逻辑放在connect回调内,确保连接建立后再触发事件:

socket.on('connect', function() {
    // 连接建立后才允许提交表单
    document.getElementById("your-form-id").addEventListener("submit", function(e) {
        e.preventDefault();
        formsubmitted();
    });
});

3. 检查Flask-SocketIO服务配置

  • 确保初始化SocketIO时开启CORS支持(根据实际域名调整):
    socketio = SocketIO(app, cors_allowed_origins="*", async_mode="eventlet")
    
  • 线上环境需使用生产级WSGI服务器(如eventlet或gevent),避免使用Flask自带的开发服务器:
    pip install eventlet
    
    启动服务时指定服务器:
    if __name__ == '__main__':
        socketio.run(app, host='0.0.0.0', port=5000, debug=False, use_reloader=False)
    

4. 移动端异常排查

  • 确保移动端网络能正常访问服务器的SocketIO端点,若使用HTTPS,需使用正规CA签发的证书,避免移动端浏览器阻止连接
  • 检查移动端浏览器对SocketIO的兼容性,可尝试降级SocketIO客户端版本适配旧浏览器

内容的提问来源于stack exchange,提问作者Carter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 09:05:16