Flutter与Frappe间Socket API连接问题求助
排查与解决步骤
1. 确认Frappe Socket服务状态与配置
Frappe默认基于Socket.IO提供实时服务,先从后端层面排除问题:
- 检查Socket.IO进程:执行
bench ps,确认存在node socketio.js相关进程;若没有,执行bench start socketio单独启动服务。 - 验证站点配置:打开站点的
site_config.json,确保包含"socketio_port": 9000(默认端口),且"host"设置为0.0.0.0或你的本地IP(如192.168.x.x),不要用localhost——模拟器/真机可能无法解析该地址。 - 测试服务可用性:用浏览器访问
http://<你的本地IP>:9000/socket.io/?EIO=4&transport=polling,若返回类似0{"sid":"xxx","upgrades":["websocket"],"pingInterval":25000,"pingTimeout":5000}的内容,说明Socket服务正常。
2. 网络与权限排查(本地测试核心)
- 设备网络映射:
- Android模拟器:将
localhost替换为10.0.2.2(模拟器本地回环映射地址); - iOS模拟器:可直接用
localhost或127.0.0.1; - 真机:必须使用电脑的本地IP(如
192.168.1.100)。
- Android模拟器:将
- 应用权限配置:
- Android:在
AndroidManifest.xml中添加<uses-permission android:name="android.permission.INTERNET"/>; - iOS:在
Info.plist中添加HTTP访问允许配置:<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict>
- Android:在
- 防火墙与代理:关闭电脑防火墙(或放行9000端口),确保Flutter应用未通过代理访问本地服务(若开启代理,需配置允许访问本地IP)。
3. 代码层面正确实现
推荐使用socket_io_client(适配Frappe Socket.IO协议)
Frappe的Socket.IO需要指定命名空间,若需认证需携带会话令牌:
import 'package:socket_io_client/socket_io_client.dart' as IO; void connectFrappeSocket() { // 替换为你的本地IP与端口 final socket = IO.io('http://192.168.1.100:9000', <String, dynamic>{ 'transports': ['websocket'], // 强制使用WebSocket,避免轮询问题 'autoConnect': false, }); // 携带Frappe会话认证(从浏览器开发者工具的Cookie中复制sid) socket.io.options['extraHeaders'] = { 'Cookie': 'sid=<你的Frappe会话ID>', }; socket.onConnect((_) { print('Socket连接成功'); // 订阅文档更新事件(替换为你的DocType) socket.emit('subscribe', {'event': 'doc_update', 'doctype': 'Your DocType'}); }); socket.on('doc_update', (data) { print('收到文档更新:$data'); }); socket.onConnectError((err) => print('连接错误:$err')); socket.onDisconnect((_) => print('Socket断开连接')); socket.connect(); }
web_socket_channel使用注意事项
需手动适配Socket.IO协议,连接URL要包含完整路径:
import 'package:web_socket_channel/web_socket_channel.dart'; void connectWithWebSocket() { final url = Uri.parse('ws://192.168.1.100:9000/socket.io/?EIO=4&transport=websocket'); final channel = WebSocketChannel.connect(url); channel.stream.listen( (message) { print('收到消息:$message'); // 手动发送Socket.IO ping帧维持连接 channel.sink.add('2'); }, onError: (error) => print('WebSocket错误:$error'), onDone: () => print('WebSocket连接关闭'), ); }
4. 日志与调试技巧
- 开启Frappe Socket.IO调试日志:执行
bench set-config -g socketio_log_level debug,再重启服务bench restart socketio,此时bench日志会输出详细的连接记录。 - 用
wscat测试连接:全局安装npm install -g wscat,执行wscat -c ws://<本地IP>:9000/socket.io/?EIO=4&transport=websocket,若能连接并在发送2后收到3(pong响应),则排除Flutter代码问题,确认后端服务正常。
5. 常见坑点
- 会话认证缺失:未携带有效Frappe会话Cookie时,服务会静默拒绝连接,需从登录后的浏览器Cookie中复制
sid添加到Socket请求头。 - 端口冲突:用
lsof -i :9000(Mac/Linux)或netstat -ano | findstr :9000(Windows)检查9000端口是否被占用,若冲突可修改Frappe的socketio_port配置。
内容的提问来源于stack exchange,提问作者Ponnusamy V
相关产品推荐
相关产品推荐

