You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何通过Python Flask代理Node.js的Socket.IO服务?

在Flask中连接Node.js Socket.IO服务的解决提示

当然可以实现Flask应用连接Node.js的Socket.IO服务,我之前也踩过代理/socket.io端点的坑,给你几个实用的解决方向:

一、Flask端配置反向代理(重点处理WebSocket)

普通的HTTP请求转发比较容易,但Socket.IO依赖WebSocket,所以得用支持WebSocket的代理方式。推荐用Werkzeug的DispatcherMiddleware配合gevent来实现:

from flask import Flask, send_static_file
from werkzeug.middleware.dispatcher import DispatcherMiddleware
from gevent.pywsgi import WSGIServer
from geventwebsocket.handler import WebSocketHandler
import requests

app = Flask(__name__)

# 提供静态页面
@app.route('/')
def serve_index():
    return send_static_file('index.html')

# 配置代理,将/socket.io请求转发到Node.js服务
proxy_app = DispatcherMiddleware(app, {
    '/socket.io': lambda environ: requests.get(
        'http://localhost:8888' + environ['PATH_INFO'],
        headers={k: v for k, v in environ.items() if k.startswith('HTTP_')},
        params=environ['QUERY_STRING'],
        stream=True
    ).raw
})

if __name__ == '__main__':
    # 用gevent的WSGI服务器,支持WebSocket
    server = WSGIServer(('0.0.0.0', 5000), proxy_app, handler_class=WebSocketHandler)
    server.serve_forever()

如果不想用gevent,也可以写一个路由转发,但要注意WebSocket的升级请求处理(不过这种方式对WebSocket的支持不如上面的方法稳定):

from flask import Flask, request, Response
import requests

app = Flask(__name__)

@app.route('/')
def index():
    return app.send_static_file('index.html')

@app.route('/socket.io/<path:path>', methods=['GET', 'POST'])
def proxy_socketio(path):
    target_url = f'http://localhost:8888/socket.io/{path}'
    # 处理查询参数
    if request.query_string:
        target_url += f'?{request.query_string.decode("utf-8")}'
    
    # 转发请求
    response = requests.request(
        method=request.method,
        url=target_url,
        headers={k: v for k, v in request.headers if k != 'Host'},
        data=request.get_data(),
        cookies=request.cookies,
        allow_redirects=False
    )
    
    # 构造响应返回
    headers = [(k, v) for k, v in response.raw.headers.items()]
    return Response(response.content, status=response.status_code, headers=headers)

二、前端Socket.IO客户端的正确配置

前端要连接Flask的地址,而不是直接连Node.js的8888端口,这样请求才会走Flask的代理:

// 你的静态页面index.html中
<script src="https://cdn.socket.io/4.7.2/socket.io.min.js"></script>
<script>
  // 连接Flask的根路径,指定socket.io的路径
  const socket = io('/', {
    path: '/socket.io'
  });

  socket.on('connect', () => {
    console.log('成功通过Flask代理连接到Socket.IO服务!');
  });

  socket.on('message', (msg) => {
    console.log('收到Node.js消息:', msg);
  });
</script>

三、Node.js Socket.IO服务的跨域配置

因为Flask运行在5000端口,Node.js在8888,必须允许Flask的域名跨域访问:

const http = require('http');
const { Server } = require('socket.io');

const server = http.createServer();
const io = new Server(server, {
  cors: {
    origin: 'http://localhost:5000', // 允许Flask的地址
    methods: ['GET', 'POST'],
    credentials: true
  }
});

io.on('connection', (socket) => {
  console.log('用户通过Flask代理连接');
  socket.emit('message', 'Hello from Node.js Socket.IO!');
});

server.listen(8888, () => {
  console.log('Socket.IO服务运行在8888端口');
});

四、调试排查技巧

  • 打开浏览器开发者工具,查看Network标签下的/socket.io请求,检查请求是否成功转发,响应状态码是否正常(101表示WebSocket升级成功)。
  • 确保Flask用支持WebSocket的服务器运行,比如用gunicorn -k gevent app:app启动,而不是Flask自带的开发服务器(自带的不支持WebSocket)。
  • 检查Node.js的日志,看是否有连接请求进来,确认代理是否生效。

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

火山引擎 最新活动