- 区块链
- Web3
【免费下载链接】web3.js
Collection of comprehensive TypeScript libraries for Interaction with the Ethereum JSON RPC API and utility functions.
web3-providers-ws是 web3.js 4.x 仓库中专用于 WebSocket 协议的 provider 子包,为通过ws:///wss://与 Ethereum 节点通信提供了基于 EIP-1193 规范、内置 JSON-RPC 请求队列与自动重连能力的连接层。本文将以该包的 README 为主线,结合 源码 与测试用例,完整讲解安装配置、WebSocketProvider构造函数参数、连接状态管理、鉴权方式、重连策略与订阅支持,帮助你在实时场景(事件订阅、推送通知)中正确选用和调优该 provider。
包定位:web3.js 的 WebSocket 连接层
web3-providers-ws是 web3.js 4.x 体系中的一个独立子包,与web3-providers-http、web3-providers-ipc并列,专门负责 WebSocket 协议的 provider 实现(见 package.json 的描述 "Websocket provider for Web3 4.x.x")。它本身不直接依赖整个 web3.js 主包,而是基于web3-types、web3-utils、web3-errors等底层库构建,因此既可以作为 web3.js 内部的默认 WebSocket provider 使用,也可以脱离主包独立安装、单独作为 EIP-1193 provider 接入。
从依赖关系看(package.json),该包的核心运行时依赖包括:
ws(^8.17.1)与isomorphic-ws(^5.0.0):跨 Node.js / 浏览器环境的 WebSocket 实现,isomorphic-ws在不同环境自动选择底层适配;web3-types(^1.7.0):提供EthExecutionAPI、Web3APIPayload等类型定义;web3-utils(^4.3.1):提供SocketProvider抽象基类、ReconnectOptions、isNullish等工具;web3-errors(^1.2.0):提供ConnectionNotOpenError、InvalidClientError等错误类型。
该包版本号当前为4.0.8,要求 Node.js>=14、npm>=6.12.0,并面向 ES2020 编译(见 package.json)。
安装与运行环境
使用 NPM 安装
npm install web3-providers-ws使用 Yarn 安装
yarn add web3-providers-ws两种安装方式等价。由于它是 web3.js monorepo 的子包,如果是在整个仓库中开发调试,也可以借助仓库根目录的 Lerna/Yarn Workspaces 机制在本地构建:在包目录执行yarn build会同时构建 CJS(lib/commonjs)、ESM(lib/esm)与类型声明(lib/types)三套产物(见 package.json)。
环境要求
- Node.js:官方要求 LTS 版本(README 标注为 Fermium,即 Node 14.x 系列,实际
engines字段为>=14); - 包管理器:Yarn 或 npm(
>=6.12.0),monorepo 场景下也可使用 Lerna; - 目标协议:连接地址必须是
ws://或wss://开头的 URL。
快速开始:创建 WebSocketProvider
最小示例
import WebSocketProvider from 'web3-providers-ws'; const provider = new WebSocketProvider('ws://localhost:8545');WebSocketProvider的构造函数签名如下(见 src/index.ts):
new WebSocketProvider( socketPath: string, socketOptions?: ClientOptions | ClientRequestArgs, reconnectOptions?: Partial<ReconnectOptions>, )socketPath:WebSocket 地址,必须是ws://或wss://前缀的合法 URL;socketOptions:可选,透传给底层ws客户端的选项(如headers、handshakeTimeout等);reconnectOptions:可选,重连策略配置(autoReconnect、delay、maxAttempts)。
后两个参数都可省略。例如只传空对象或undefined:
const provider = new WebSocketProvider('ws://localhost:8545', {}, { delay: 500, autoReconnect: true, maxAttempts: 10, });URL 校验
构造函数会对socketPath做严格校验:只有以ws://或wss://(大小写不敏感)开头的字符串才会被接受,否则抛出InvalidClientError。该校验逻辑位于 src/index.ts:
protected _validateProviderPath(providerUrl: string): boolean { return typeof providerUrl === 'string' ? /^ws(s)?:\/\//i.test(providerUrl) : false; }单元测试 test/unit/web_socket_provider.test.ts 与测试数据 test/fixtures/test_data.ts 验证了这一点:
- 合法示例:
ws://localhost:8545、ws://localhost、wss://foo.com、ws://foo.com:8545等; - 非法示例:
htt://localhost:8545、http//localhost:8545、ipc://localhost:8545、空字符串、null、undefined、数字42等,均会抛出Client URL "..." is invalid.错误。
注意:
ipc://前缀不属于本包职责,IPC 连接应使用web3-providers-ipc。
核心 API 与连接生命周期
WebSocketProvider继承自web3-utils中的抽象基类SocketProvider(见 web3-utils/src/socket_provider.ts),后者又继承自 EIP-1193 provider。因此该 provider 天然具备以下能力(单元测试 test/unit/web_socket_provider.test.ts 逐一验证了这些方法的存在):
| API | 说明 |
|---|---|
request(payload) | 发起 JSON-RPC 请求,返回 Promise |
getStatus() | 返回'connecting'/'connected'/'disconnected' |
connect()/disconnect(code?, data?) | 手动建立 / 关闭连接 |
safeDisconnect(code?, data?, forceDisconnect?, ms?) | 等待请求队列清空后再断开(forceDisconnect=true时最多等待 5 次重试后强制清空) |
reset() | 清空 pending / sent 请求队列并重置监听器 |
supportsSubscriptions() | 恒返回true,表示支持订阅 |
on / once / removeListener / removeAllListeners | 事件监听(connect、disconnect、message、error等) |
getPendingRequestQueueSize()/getSentRequestsQueueSize() | 查看请求队列大小 |
SocketConnection | 暴露底层 WebSocket 实例 |
连接状态机
getStatus()的实现直接映射底层 WebSocket 的readyState(见 src/index.ts):
CONNECTING→ 返回'connecting';OPEN→ 返回'connected';- 其他(如
CLOSING、CLOSED)→ 返回'disconnected'。
集成测试 test/integration/web_socket_provider_integration.test.ts 完整覆盖了三种状态的流转:新建即connecting,连接建立后connected,调用disconnect()后disconnected。
请求与响应处理
request()是核心调用入口,其逻辑位于基类 socket_provider.ts:
- 若连接已断开,自动重新
connect(); - 若请求 ID 缺失,抛出
Web3WSProviderError('Request Id not defined'); - 若同一 ID 已存在于
_sentRequestsQueue,抛出RequestAlreadySentError; - 为每个请求创建
Web3DeferredPromise并封装为SocketRequestItem; - 连接尚未建立(
connecting)时,请求进入_pendingRequestsQueue,待open事件触发后由_sendPendingRequests()统一补发(见 socket_provider.ts); - 连接就绪时直接通过
_sendToSocket发送——底层实现为this._socketConnection?.send(JSON.stringify(payload))(见 src/index.ts),并在此前检查连接状态,断开时抛出ConnectionNotOpenError。
收到消息时,_parseResponses会借助ChunkResponseParser解析可能被分块(chunked)返回的响应,并按请求 ID 从_sentRequestsQueue中匹配、resolve 对应的 deferred promise;若响应是*_subscription类型的通知,则作为message事件向外抛出(见 socket_provider.ts)。集成测试 test/integration/web_socket_provider_integration.test.ts 验证了在同一连接上并发发送多个请求(eth_getBalance、eth_mining、eth_hashrate)并正确按 ID 取回响应。
socketOptions:连接选项与鉴权
第二个构造参数socketOptions会被原样透传给isomorphic-ws的 WebSocket 客户端(见 src/index.ts):
protected _openSocketConnection() { this._socketConnection = new WebSocket( this._socketPath, undefined, this._socketOptions && Object.keys(this._socketOptions).length === 0 ? undefined : this._socketOptions, ); }注意:当传入的是空对象时,会转为undefined再透传,避免干扰底层客户端默认行为。
常见选项示例
const provider = new WebSocketProvider('wss://node.example.com', { headers: { // 若节点要求 API Key 放在请求头中,例如: 'x-api-key': '<Api key>', }, handshakeTimeout: 1500, // 握手超时(毫秒) followRedirects: true, // 跟随重定向 maxRedirects: 3, // 最大重定向次数 perMessageDeflate: true, // 启用消息压缩 });测试数据 test/fixtures/test_data.ts 中的wsProviderOptions给出了followRedirects、handshakeTimeout、maxRedirects、perMessageDeflate等可配置项,单元测试 test/unit/web_socket_provider.test.ts 验证了携带这些选项实例化不会抛错。
通过 headers 实现鉴权
最常见的鉴权场景是把凭证放进headers。以 Basic Auth 为例,集成测试 test/integration/basic_auth.test.ts 展示了一个校验流程:服务端检查Authorization头是否包含Basic前缀,否则销毁连接。与之对应的客户端侧配置即:
const credentials = Buffer.from('username:password').toString('base64'); const provider = new WebSocketProvider('ws://localhost:3000', { headers: { Authorization: `Basic ${credentials}`, }, });同理,对于使用 API Key 的商业节点(如 QuickNode、Infura 等),可将密钥放入headers中的自定义字段(如'x-api-key'),与源码注释中的示例一致(见 src/index.ts)。
reconnectOptions:自动重连策略
第三个构造参数控制断线重连行为。ReconnectOptions类型与默认值定义在 web3-utils/src/socket_provider.ts:
export type ReconnectOptions = { autoReconnect: boolean; delay: number; maxAttempts: number; }; const DEFAULT_RECONNECTION_OPTIONS = { autoReconnect: true, delay: 5000, maxAttempts: 5, };| 参数 | 默认值 | 说明 |
|---|---|---|
autoReconnect | true | 是否在异常断开后自动重连 |
delay | 5000 | 每次重连尝试前的等待时间(毫秒) |
maxAttempts | 5 | 最大重连尝试次数 |
构造函数会通过展开运算符将用户配置合并到默认值之上(见 socket_provider.ts),因此可只传部分字段。集成测试 test/integration/reconnection.test.ts 验证了默认值确实为{ autoReconnect: true, delay: 5000, maxAttempts: 5 }。
重连触发条件
重连逻辑在_onCloseEvent中判断(见 src/index.ts):
if ( this._reconnectOptions.autoReconnect && (![1000, 1001].includes(event.code) || !event.wasClean) ) { this._reconnect(); return; }即:当自动重连开启,且关闭码不是正常的 1000(正常关闭)或 1001(服务端下线),或关闭并非干净(wasClean为 false)时,触发重连。正常关闭(如调用disconnect())则走清理队列、移除监听器、派发disconnect事件的流程。
_reconnect()的实现(见 socket_provider.ts)会:
- 拒绝所有
_sentRequestsQueue中的请求并抛出PendingRequestsOnReconnectingError; - 在
delay毫秒后重新connect(); - 若重连次数达到
maxAttempts上限,则清空队列并抛出MaxAttemptsReachedOnReconnectingError。
重连配置示例
const provider = new WebSocketProvider( 'ws://localhost:8545', {}, { delay: 500, // 每 500ms 尝试一次 autoReconnect: true, maxAttempts: 10, // 最多尝试 10 次 }, );需要快速失败(例如测试或容错场景)时可显式关闭重连,如集成测试中常用的{ delay: 1, autoReconnect: false, maxAttempts: 1 }(见 test/integration/web_socket_provider_integration.test.ts);与此相对,test/integration/reconnection.test.ts 使用{ delay: 500, autoReconnect: true, maxAttempts: 100 }验证长时间重连场景。
事件订阅:实时推送的基础
由于 WebSocket 是双向通道,该 provider 支持 JSON-RPC 订阅(eth_subscribe/eth_unsubscribe)。supportsSubscriptions()恒返回true(见 socket_provider.ts),单元测试也对此做了断言(见 test/unit/web_socket_provider.test.ts)。
订阅推送的消息会以*_subscription结尾的方法名被识别为通知,通过message事件向外派发。监听方式:
provider.on('message', (result) => { console.log('收到订阅推送:', result); });其他可用事件包括:
connect:连接建立成功(对应open事件,见 socket_provider.ts);disconnect:连接关闭,回调参数为ProviderRpcError(含code与reason);error:底层 WebSocket 出错,或请求失败时派发(见 socket_provider.ts)。
集成测试 test/integration/web_socket_provider_integration.test.ts 完整覆盖了message、error、connect、disconnect四个事件的订阅,并验证了连接未建立时调用request()会抛出Connection not open错误。
与 web3.js 主包集成
web3-providers-ws不仅可独立使用,也是 web3.js 4.x 主包中eth模块默认使用的 WebSocket provider。你可以直接在Web3实例上指定:
import Web3 from 'web3'; import WebSocketProvider from 'web3-providers-ws'; const provider = new WebSocketProvider('wss://node.example.com', { headers: { 'x-api-key': '<Api key>' }, }); const web3 = new Web3(provider); // 之后即可使用 web3.eth.getBlockNumber()、web3.eth.subscribe(...) 等 API这样既能复用 provider 的自动重连与请求队列,又能借助主包获得合约、交易、订阅等完整 API。
包内常用脚本
开发本包时可使用 package.json 中定义的脚本:
| Script | 说明 |
|---|---|
clean | 使用rimraf删除dist/与lib/ |
build | 使用tsc构建本包及其依赖包(CJS/ESM/类型三套产物) |
lint | 使用eslint检查代码 |
lint:fix | 使用eslint检查并自动修复 |
format | 使用prettier格式化代码 |
test | 运行单元测试(jest,配置见test/unit/jest.config.js) |
test:integration | 运行test/integration下的集成测试(需连接真实节点,测试中通过getSystemTestProviderUrl()获取) |
test:unit | 仅运行单元测试 |
单元测试在test/unit下(mock 了isomorphic-ws),集成测试在test/integration下(依赖真实 WebSocket 节点,并通过describeIf(isWs)条件执行),源码入口为 src/index.ts,默认导出WebSocketProvider。
小结
web3-providers-ws为 web3.js 4.x 提供了开箱即用的 WebSocket 连接能力:通过new WebSocketProvider(url, socketOptions?, reconnectOptions?)三参数构造即可完成连接、鉴权与重连策略配置;其基于 EIP-1193 的SocketProvider基类封装了请求队列、分块响应解析、自动重连与订阅分发,适合事件监听、实时推送等场景。在使用时,请重点根据节点要求配置headers(鉴权)、按网络稳定性调优reconnectOptions(重连间隔与次数上限),并善用connect/disconnect/message/error事件掌握连接生命周期。
- 区块链
- Web3
【免费下载链接】web3.js
Collection of comprehensive TypeScript libraries for Interaction with the Ethereum JSON RPC API and utility functions.
相关推荐
终极web3.py Provider配置指南:HTTP、IPC和WebSocket连接详解
终极web3.py Provider配置指南:HTTP、IPC和WebSocket连接详解 web3.py是Python开发者与以太坊区块链交互的首选工具,而P
Web3区块链Web3.js Provider 事件监听指南:EIP-1193 事件模型与 WebSocket/IPC 底层连接实战
Web3.js Provider 事件监听指南:EIP 1193 事件模型与 WebSocket/IPC 底层连接实战 部分 Provider(如 WebSoc
区块链Web3Web3.js Providers 完全指南:HTTP、WebSocket、IPC 与 EIP-1193 注入式 Provider 的初始化与配置
Web3.js Providers 完全指南:HTTP、WebSocket、IPC 与 EIP 1193 注入式 Provider 的初始化与配置 导读 在 w
区块链Web3
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考