Flutter连接Laravel Reverb遇WebSocket报错:Pong回复超时
解决Flutter连接Laravel Reverb时的"Pong reply not received in time"错误
错误原因
- 未响应服务器Ping帧:Laravel Reverb基于Pusher协议运行,会定期向客户端发送Ping帧,要求客户端回复Pong。若Flutter客户端未监听并回复这些Ping,服务器会判定连接超时,抛出4201错误。
- 默认WebSocket通道不兼容Pusher心跳机制:
IOWebSocketChannel默认未实现Pusher风格的Ping/Pong自动交互,需要手动处理。 - 连接闲置超时:客户端长时间无数据发送时,服务器的心跳检测机制会触发超时判定。
修复方案
1. 监听Ping帧并主动回复Pong
修改代码,添加Ping帧监听与Pong回复逻辑:
import 'dart:convert'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:web_socket_channel/io.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; class ReverbTestWidget extends StatefulWidget { const ReverbTestWidget({super.key}); @override State<ReverbTestWidget> createState() => _ReverbTestWidgetState(); } class _ReverbTestWidgetState extends State<ReverbTestWidget> { late IOWebSocketChannel channel; @override void initState() { super.initState(); _initWebSocket(); } void _initWebSocket() { channel = IOWebSocketChannel.connect( 'ws://localhost:8080/app/wdkuwjwxw78hbp6sax2c', ); channel.stream.listen( (message) { // 处理字符串消息 if (message is String) { print('收到消息: $message'); } // 处理二进制Ping帧 else if (message is List<int>) { final frame = WebSocketFrame.fromBytes(message); // WebSocket Ping帧的操作码为9 if (frame.opcode == 9) { // 回复Pong帧(操作码为10) channel.sink.add(WebSocketFrame.pong(frame.payload).toBytes()); } } }, onError: (error) { print('连接错误: $error'); _reconnect(); }, onDone: () { print('连接已关闭'); _reconnect(); }, ); // 订阅频道 channel.sink.add(json.encode({ "event": "pusher:subscribe", "data": {"channel": "home"}, })); } // 重连逻辑 void _reconnect() async { await Future.delayed(const Duration(seconds: 3)); if (mounted) { setState(() { _initWebSocket(); }); } } @override void dispose() { channel.sink.close(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Reverb 连接测试')), body: StreamBuilder( stream: channel.stream, builder: (context, snapshot) { return Center( child: Text(snapshot.hasData ? '消息: ${snapshot.data}' : '等待连接...'), ); }, ), ); } }
2. 调整Laravel Reverb超时配置(可选)
若需要延长超时时间,修改config/reverb.php中的参数:
return [ // 其他配置... 'options' => [ 'ping_interval' => 60, // 调整Ping发送间隔(单位:秒) 'ping_timeout' => 30, // 调整Pong等待超时时间(单位:秒) ], ];
修改后重启Reverb服务生效。
3. 手动发送心跳维持连接
若自动Ping/Pong处理存在问题,可定期向服务器发送心跳事件:
// 在_initWebSocket方法中添加定时心跳 Timer.periodic(const Duration(seconds: 30), (timer) { if (mounted && channel.sink != null) { channel.sink.add(json.encode({ "event": "pusher:ping", "data": {}, })); } });
关键注意点
- Pusher协议的Ping/Pong为二进制帧,需监听
List<int>类型消息进行处理,而非字符串。 - 重连逻辑可避免连接意外断开后用户需手动重启应用,提升稳定性。
- 超时参数调整需平衡资源消耗与连接稳定性,过长间隔可能导致连接被中间件(如Nginx)主动断开。
内容的提问来源于stack exchange,提问作者Solayman Mousa
相关产品推荐
相关产品推荐

