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

Python WebSocket服务器在AWS Elastic Beanstalk上无法运行求助

问题:Elastic Beanstalk单实例部署下WebSocket推送失败

我是编程和AWS新手,表述不当请见谅。正在开发Kotlin应用,后端Python服务部署在Elastic Beanstalk,除WebSocket数据传输外其他功能正常。

测试场景:点击应用按钮向domain/send_test发送POST请求,后端应通过WebSocket向前端推送"TEST RECEIVED!!!!!"。目前能看到后端send_test函数被调用,但前端收不到消息,后端日志显示已发送数据包。

实际需求:后端某函数需立即返回值,同时开启线程调用外部API,待API返回结果后通过WebSocket推送给前端。

环境为Single Instance (Free Tier),无负载均衡器,尝试配置WebSocket相关设置但旧教程不匹配新版界面,已卡一周。


后端简化代码

# Import...
app = application = Flask(__name__)
ping_timeout = 120
ping_interval = 60
socketio = SocketIO(application, cors_allowed_origins="*", engineio_logger=True, allowEIO3=True, ping_timeout=ping_timeout, ping_interval=ping_interval)
logging.basicConfig(level=logging.DEBUG)

@application.route('/send_test', methods=['POST'])
def send_test():
    socketio.emit('test', {'response': 'TEST RECEIVED!!!!!'})
    return "Success", 200

前端简化代码

class MainActivity : AppCompatActivity(), TextToSpeech.OnInitListener, NavigationView.OnNavigationItemSelectedListener {
    private lateinit var socket: Socket
    override fun onCreate(savedInstanceState: Bundle?) {
        connectWebSocket()
    }

    private fun connectWebSocket() {
        Log.d("MainActivity", "connectwebsocket called")
        val socketUrl = "ws://travel32.us-east-1.elasticbeanstalk.com"
        val job = Job()
        val coroutineScope = CoroutineScope(Dispatchers.IO + job)
        IO.setDefaultOkHttpWebSocketFactory(OkHttpClient.Builder().addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)).build())
        IO.setDefaultOkHttpCallFactory(OkHttpClient.Builder().addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)).build())
        coroutineScope.launch {
            socket = IO.socket(socketUrl, IO.Options().apply {
                reconnection = true
                reconnectionAttempts = Integer.MAX_VALUE
                reconnectionDelay = 1000 // 1 second
                reconnectionDelayMax = 5000 // 5 seconds
            })
            socket.connect()
            Log.d("MainActivity", "WebSocket connected")

            socket.on("test", testsocket)
            socket.on(Socket.EVENT_CONNECT, onConnect)
            socket.on(Socket.EVENT_DISCONNECT, onDisconnect)
            socket.on(Socket.EVENT_CONNECT_ERROR, onError)
        }
    }

    private val testsocket = Emitter.Listener { args ->
        runOnUiThread {
            val testresponse = args[0] as JSONObject
            Log.d("MainActivity", "Received TEST response: $testresponse")
        }
    }
}

后端web.stdout.log日志

May 14 14:19:27 ip-172-31-13-189 web[2211]: jxIFnNaeB7crO36TAAAC: Sending packet MESSAGE data 2["test",{"response":"TEST RECEIVED!!!!!"}]
May 14 14:19:27 ip-172-31-13-189 web[2211]: INFO:engineio.server:jxIFnNaeB7crO36TAAAC: Sending packet MESSAGE data 2["test",{"response":"TEST RECEIVED!!!!!"}]
May 14 14:19:39 ip-172-31-13-189 web[2211]: jxIFnNaeB7crO36TAAAC: Sending packet MESSAGE data 2["test",{"response":"TEST RECEIVED!!!!!"}]
May 14 14:19:39 ip-172-31-13-189 web[2211]: INFO:engineio.server:jxIFnNaeB7crO36TAAAC: Sending packet MESSAGE data 2["test",{"response":"TEST RECEIVED!!!!!"}]
May 14 14:20:01 ip-172-31-13-189 web[2211]: jxIFnNaeB7crO36TAAAC: Sending packet PING data None
May 14 14:20:01 ip-172-31-13-189 web[2211]: INFO:engineio.server:jxIFnNaeB7crO36TAAAC: Sending packet PING data None
May 14 14:20:02 ip-172-31-13-189 web[2211]: luoag_u_sK4lq15kAAAE: Sending packet OPEN data {'sid': 'luoag_u_sK4lq15kAAAE', 'upgrades': ['websocket'], 'pingTimeout': 120000, 'pingInterval': 60000}
May 14 14:20:02 ip-172-31-13-189 web[2211]: INFO:engineio.server:luoag_u_sK4lq15kAAAE: Sending packet OPEN data {'sid': 'luoag_u_sK4lq15kAAAE', 'upgrades': ['websocket'], 'pingTimeout': 120000, 'pingInterval': 60000}
May 14 14:20:02 ip-172-31-13-189 web[2211]: luoag_u_sK4lq15kAAAE: Received packet MESSAGE data 0
May 14 14:20:02 ip-172-31-13-189 web[2211]: INFO:engineio.server:luoag_u_sK4lq15kAAAE: Received packet MESSAGE data 0
May 14 14:20:02 ip-172-31-13-189 web[2211]: luoag_u_sK4lq15kAAAE: Sending packet MESSAGE data 0{"sid":"1FGFeiKmah61v5UEAAAF"}
May 14 14:20:02 ip-172-31-13-189 web[2211]: INFO:engineio.server:luoag_u_sK4lq15kAAAE: Sending packet MESSAGE data 0{"sid":"1FGFeiKmah61v5UEAAAF"}
May 14 14:20:02 ip-172-31-13-189 web[2211]: luoag_u_sK4lq15kAAAE: Received request to upgrade to websocket
May 14 14:20:02 ip-172-31-13-189 web[2211]: INFO:engineio.server:luoag_u_sK4lq15kAAAE: Received request to upgrade to websocket
May 14 14:20:03 ip-172-31-13-189 web[2211]: luoag_u_sK4lq15kAAAE: Upgrade to websocket successful
May 14 14:20:03 ip-172-31-13-189 web[2211]: INFO:engineio.server:luoag_u_sK4lq15kAAAE: Upgrade to websocket successful

问题分析与解决方案

1. 核心问题:连接SID不匹配

从日志可见,后端发送消息使用的连接SID是jxIFnNaeB7crO36TAAAC,而前端新建立的连接SID是luoag_u_sK4lq15kAAAE,两者不属于同一个连接会话,导致前端收不到消息。

2. 针对性修复步骤

(1)调整前端连接地址与监听顺序

  • 将前端socketUrl改为http://travel32.us-east-1.elasticbeanstalk.com,让Socket.IO客户端自动处理握手与WebSocket升级,而非直接使用ws://协议。
  • 先添加事件监听再调用connect(),避免异步连接导致的监听丢失:
    coroutineScope.launch {
        socket = IO.socket(socketUrl, IO.Options().apply {
            reconnection = true
            reconnectionAttempts = Integer.MAX_VALUE
            reconnectionDelay = 1000
            reconnectionDelayMax = 5000
        })
        // 先绑定所有监听事件
        socket.on("test", testsocket)
        socket.on(Socket.EVENT_CONNECT) {
            runOnUiThread { Log.d("MainActivity", "WebSocket连接成功") }
        }
        socket.on(Socket.EVENT_DISCONNECT) {
            runOnUiThread { Log.d("MainActivity", "WebSocket断开连接") }
        }
        socket.on(Socket.EVENT_CONNECT_ERROR) { args ->
            runOnUiThread { Log.e("MainActivity", "连接错误: ${args[0]}") }
        }
        // 再发起连接
        socket.connect()
    }
    

(2)配置Elastic Beanstalk代理支持WebSocket

单实例环境下,默认反向代理(Apache/Nginx)未开启WebSocket升级支持,需添加配置文件:
在项目根目录创建.ebextensions文件夹,新增01-websocket.config:

  • Apache环境:
    files:
      "/etc/httpd/conf.d/websocket.conf":
        mode: "000644"
        owner: root
        group: root
        content: |
          LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
          ProxyPass "/socket.io/" "ws://localhost:5000/socket.io/"
          ProxyPassReverse "/socket.io/" "ws://localhost:5000/socket.io/"
    
  • Nginx环境:
    files:
      "/etc/nginx/conf.d/websocket.conf":
        mode: "000644"
        owner: root
        group: root
        content: |
          location /socket.io/ {
              proxy_pass http://localhost:5000;
              proxy_http_version 1.1;
              proxy_set_header Upgrade $http_upgrade;
              proxy_set_header Connection "upgrade";
              proxy_set_header Host $host;
          }
    
    打包项目时将.ebextensions文件夹一并上传。

(3)修复后端消息推送逻辑

测试场景下,使用广播推送需确保前端连接处于活跃状态;实际需求中,需定向推送API结果,可通过存储客户端SID实现:

from flask_socketio import emit, async_to_sync
import threading
import requests

# 存储客户端SID,生产环境建议用数据库或缓存
active_clients = {}

@socketio.on('connect')
def handle_connect():
    active_clients[request.sid] = True
    print(f"客户端连接: {request.sid}")

@socketio.on('disconnect')
def handle_disconnect():
    active_clients.pop(request.sid, None)
    print(f"客户端断开: {request.sid}")

def call_external_api(sid):
    # 调用外部API
    try:
        result = requests.get("https://your-external-api-url.com")
        async_to_sync(socketio.emit)('api_result', {'data': result.json()}, room=sid)
    except Exception as e:
        async_to_sync(socketio.emit)('api_error', {'error': str(e)}, room=sid)

@application.route('/trigger_api', methods=['POST'])
def trigger_api():
    # 从请求中获取客户端SID(前端需传递socket.id)
    sid = request.json.get('sid')
    if sid in active_clients:
        threading.Thread(target=call_external_api, args=(sid,)).start()
        return "API调用已启动", 200
    return "无效的客户端连接", 400

(4)版本兼容性检查

后端设置了allowEIO3=True,需确保前端Socket.IO客户端版本为v2.x或v3.x(v4.x默认使用EIO v4协议),避免协议不兼容导致连接异常。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 03:38:07