使用ethers.js 6.7.1监听合约事件时,无事件触发WebSocket RPC断开求助
Ethers 6.7.1 WebSocket 监听断连问题解决方案
问题核心
ethers 6.x 版本对 WebSocketProvider 的重连逻辑做了调整,默认保活机制在长时间无事件触发时会失效,再加上多数节点服务商的 WebSocket 连接会在闲置30分钟左右主动断开,导致监听停止。
有效解决方法
1. 手动实现重连逻辑
通过监听 provider 的错误/关闭事件,触发重新初始化连接和监听,确保断开后自动恢复:
let provider; let contract; let eventHandler; // 初始化连接与监听的通用函数 function setupConnection() { // 清理旧资源,避免内存泄漏 if (provider) { provider.removeAllListeners(); provider.destroy(); } if (contract) { contract.removeAllListeners("EventName"); } // 新建连接 provider = new ethers.WebSocketProvider(providerUrl); contract = new ethers.Contract(contractAddress, contractABI, provider); // 注册事件处理 eventHandler = (data) => { // 你的事件处理逻辑 ...rest of the code }; contract.on("EventName", eventHandler); // 监听连接异常,触发重连 provider.on("error", (err) => { console.error("连接出错,准备重连:", err); setTimeout(setupConnection, 5000); }); provider.on("close", (code, reason) => { console.error(`连接关闭(状态码: ${code},原因: ${reason}),准备重连`); setTimeout(setupConnection, 5000); }); } // 首次初始化 setupConnection();
2. 修复心跳机制(确保触发实际通信)
之前的心跳可能没真正触发 WebSocket 消息发送,改用 provider 的 send 方法主动发送请求,维持连接:
// 启动心跳,每分钟一次 setInterval(async () => { try { // 检查WebSocket是否处于连接状态 if (provider && provider._websocket?.readyState === 1) { // 发送eth_blockNumber请求作为心跳 await provider.send("eth_blockNumber", []); } } catch (err) { console.error("心跳发送失败:", err); } }, 60000);
建议将心跳间隔设置为小于节点的闲置超时时间(比如节点30分钟超时,就设为25分钟一次,或更频繁的1分钟)。
3. 检查节点服务商配置
多数以太坊节点服务商(如Alchemy、Infura)对 WebSocket 闲置连接有明确超时限制,可登录服务商后台查看是否支持调整超时时间,或更换为允许更长闲置时长的节点服务。
注意事项
- 重连时必须清理旧的 provider 和 contract 实例,避免内存泄漏和重复监听
- 事件监听需在每次重连后重新注册,旧实例的监听会随连接断开失效
内容的提问来源于stack exchange,提问作者Webby
相关产品推荐
相关产品推荐

