web3.js 的 HTTP 传输层进化论:从变更日志到源码,读懂 web3-providers-http 的每一次关键升级
2026/9/21 0:11:27 网站建设 项目流程

web3.js 的 HTTP 传输层进化论:从变更日志到源码,读懂 web3-providers-http 的每一次关键升级

【免费下载链接】web3.jsCollection of comprehensive TypeScript libraries for Interaction with the Ethereum JSON RPC API and utility functions.项目地址: https://gitcode.com/gh_mirrors/we/web3.js

本篇文章以 packages/web3-providers-http/CHANGELOG.md 为核心骨架,逐条还原web3-providers-http从 4.0 系列 alpha 到 4.2.0 的演进脉络,并深入其源码(src/index.ts)、类型定义(src/types.ts)、打包配置(package.json)与单元测试(test/unit),说明每次版本变更背后的工程动因与对使用者的实际影响。读完你将掌握HttpProvider的完整实现原理、配置方式、测试方法,以及升级到 4.1.0 / 4.2.0 时值得注意的行为变化。

一、包定位与变更日志规范

web3-providers-http是 web3.js 4.x 的官方 HTTP 协议 Provider 子包,负责将 Web3 JSON-RPC 请求通过 HTTP POST 发送到以太坊节点,并解析 JSON-RPC 响应。它基于Web3BaseProvider基类实现,是 web3.js 与 HTTP 节点交互的默认传输通道——在 web3-core/src/web3_request_manager.ts 中,HttpProvider被直接引入并作为默认 Provider 使用;同时它也通过 packages/web3/src/index.ts 的export { HttpProvider }与 packages/web3/src/providers.exports.ts 的export * as http暴露给顶层 web3 包使用者。

该 CHANGELOG 遵循 Keep a Changelog 规范(Added/Changed/Deprecated/Removed/Fixed/Security分类),并遵循语义化版本控制(Semantic Versioning):4.0.x 为 4.0 正式版前的 alpha/rc 迭代,4.1.0 与 4.2.0 为向后兼容的次版本功能增强,文件末尾保留了[Unreleased]区块用于登记尚未发布的变更。

二、4.0 系列:从 alpha 到正式发布的工程化打磨

CHANGELOG 中 4.0.1 之前的五次预发布(alpha.2 ~ alpha.5)内容全部集中在依赖升级与构建产物调整上,其中4.0.1-alpha.4是一次影响所有使用者的结构变更:

mainandfilesentries inpackage.jsonchanged tolib/directory fromdist/(#5739)

即包的发布产物目录由dist/调整为lib/。对照当前 package.json 可以验证这一变更的最终形态:

"main": "./lib/commonjs/index.js", "module": "./lib/esm/index.js", "exports": { ".": { "types": "./lib/types/index.d.ts", "import": "./lib/esm/index.js", "require": "./lib/commonjs/index.js" } }, "files": ["lib/**/*", "src/**/*"]

这里的exports字段为 Node.js 的「条件导出」,让 ESM(import)与 CommonJS(require)使用者各自获得对应产物,TypeScript 类型则统一指向lib/types/index.d.ts

4.0.1-rc.0的关键变更是「为HttpProvider添加了命名导出(named export)」(#5771)。在 src/index.ts 文件末尾可以看到export { HttpProvider };export { HttpProviderOptions },这意味着除了默认导出外,还支持:

import { HttpProvider } from 'web3-providers-http'; import HttpProviderDefault from 'web3-providers-http'; // 默认导出同样可用

4.0.1-rc.1则引入两项与源码可分发性直接相关的变更:

  • Added source files (#5956)package.jsonfiles字段包含"src/**/*",将 TypeScript 源码一并发布到 npm,便于使用者调试与查看实现;
  • Added hybrid build (ESM and CJS) of library (#5904):构建脚本(见package.jsonscripts)采用三路并行编译:
"build:cjs": "tsc --build tsconfig.cjs.json && echo '{\"type\": \"commonjs\"}' > ./lib/commonjs/package.json", "build:esm": "tsc --build tsconfig.esm.json && echo '{\"type\": \"module\"}' > ./lib/esm/package.json", "build:types": "tsc --build tsconfig.types.json"

注意 CJS 与 ESM 产物各自通过向子目录写入{"type": "commonjs"}/{"type": "module"}声明模块格式,避免 Node.js 对.js扩展名的格式歧义——这是 npm 包混合构建的经典做法。配置文件可参见 tsconfig.cjs.json、tsconfig.esm.json 与 tsconfig.types.json。此外engines字段声明了运行环境下限:node >= 14npm >= 6.12.0

三、4.1.0:升级 cross-fetch v4,解锁 Service Worker 环境

4.1.0 是一次值得重点关注的行为变更:

  • Bump cross-fetch to version 4 (#6463).
  • Fix issue lquixada/cross-fetch#78, enabling to run web3.js in service worker (#6463)

HttpProvider的底层网络层完全依赖cross-fetch这个同构 fetch 实现,这一点在 src/index.ts 顶部即可确认:import fetch from 'cross-fetch';。旧版 cross-fetch 在 Service Worker 环境中会因依赖XMLHttpRequest而报错,导致 web3.js 无法在 Service Worker 中运行;升级到 v4 后,请求路径改为原生fetch实现,从而修复了该问题。

当前 package.json 中"cross-fetch": "^4.0.0"印证了这一升级的落地。对使用者的实际意义是:4.1.0 及以上版本可以在 Service Worker、浏览器扩展等受限网络环境中使用HttpProvider;若你仍在使用 4.0.x,则需注意此类环境下的兼容性限制。

四、4.2.0:ResponseError 携带 HTTP statusCode

4.2.0 引入的是错误信息的增强:

AddedstatusCodeof response in ResponseError,statusCodeis optional property in ResponseError.

ResponseError定义在 packages/web3-errors/src/errors/response_errors.ts,核心结构如下:

export class ResponseError<ErrorType = unknown, RequestType = unknown> extends BaseWeb3Error { public code = ERR_RESPONSE; public data?: ErrorType | ErrorType[]; public request?: JsonRpcPayload<RequestType>; public statusCode?: number; // 4.2.0 新增的可选属性 public constructor( response: JsonRpcResponse<unknown, ErrorType>, message?: string, request?: JsonRpcPayload<RequestType>, statusCode?: number, ) { /* ... */ } }

statusCode被声明为可选属性statusCode?: number),通过构造函数第四个参数传入,并同步出现在toJSON()的序列化结果中(便于日志与错误上报)。而真正把 HTTP 状态码灌入异常的地方,正是 src/index.ts 的request()方法:

if (!response.ok) { throw new ResponseError(await response.json(), undefined, undefined, response.status); }

当节点返回非 2xx 状态时(如 400、429、500),HTTP 状态码会作为第四个参数传入ResponseError。因此从 4.2.0 起,开发者可以在 catch 中直接区分限流(429)、参数错误(400)与节点故障(500)等不同场景,例如:

import { ResponseError } from 'web3-errors'; try { await web3.eth.getBalance('0x407d73d8a49eeb85d32cf465507dd71d507100c1'); } catch (err) { if (err instanceof ResponseError && err.statusCode === 429) { // 触发速率限制,可在此实现退避重试 } }

五、HttpProvider 核心实现解析

HttpProvider的完整实现只有百余行(src/index.ts),但承载了 web3.js 与 HTTP 节点交互的全部逻辑,值得逐段拆解。

5.1 构造与 URL 校验

export default class HttpProvider< API extends Web3APISpec = EthExecutionAPI, > extends Web3BaseProvider<API> { private readonly clientUrl: string; private readonly httpProviderOptions: HttpProviderOptions | undefined; public constructor(clientUrl: string, httpProviderOptions?: HttpProviderOptions) { super(); if (!HttpProvider.validateClientUrl(clientUrl)) throw new InvalidClientError(clientUrl); this.clientUrl = clientUrl; this.httpProviderOptions = httpProviderOptions; } private static validateClientUrl(clientUrl: string): boolean { return typeof clientUrl === 'string' ? /^http(s)?:\/\//i.test(clientUrl) : false; } }

URL 校验使用正则^http(s)?:\/\//i只接受http://https://开头的字符串。测试用例 test/unit/constructor.test.ts 与 test/fixtures/test_data.ts 给出了完整边界:

  • 合法:http://localhost:8545http://www.localhosthttps://foo.comhttp://foo.com:8545等;
  • 非法:htt://localhost:8545http//localhost:8545ws://localhost:8545、空字符串、nullundefined、数字42等,均会抛出InvalidClientError,错误消息形如`Client URL "${invalidClient}" is invalid.`

注意ws://属于 WebSocket 协议,必须使用web3-providers-ws包,而非本包。

5.2 请求处理流程:request()

public async request< Method extends Web3APIMethod<API>, ResultType = Web3APIReturnType<API, Method>, >( payload: Web3APIPayload<API, Method>, requestOptions?: RequestInit, ): Promise<JsonRpcResponseWithResult<ResultType>> { const providerOptionsCombined = { ...this.httpProviderOptions?.providerOptions, ...requestOptions, }; const response = await fetch(this.clientUrl, { ...providerOptionsCombined, method: 'POST', headers: { ...providerOptionsCombined.headers, 'Content-Type': 'application/json', }, body: JSON.stringify(payload), }); if (!response.ok) { throw new ResponseError(await response.json(), undefined, undefined, response.status); } return (await response.json()) as JsonRpcResponseWithResult<ResultType>; }

请求流程的关键细节:

  1. 配置合并优先级:实例化时传入的httpProviderOptions.providerOptions与单次调用的requestOptions做浅合并,后者覆盖前者;
  2. 强制 POST + JSON:无论传入的 options 如何,method一律覆盖为POSTheaders中确保存在Content-Type: application/jsonbodyJSON.stringify(payload)(即标准 JSON-RPC 载荷);
  3. 非 2xx 抛错!response.ok时解析响应体并抛出携带statusCodeResponseError
  4. 成功响应直接反序列化:返回JsonRpcResponseWithResult<ResultType>

5.3 明确不支持的能力:HTTP 无订阅、无连接生命周期

HttpProvider对事件与连接类方法一律抛MethodNotImplementedError,因为 HTTP 是无状态请求-响应协议,无法承载订阅或持久连接:

  • supportsSubscriptions()返回false——这是与WebSocketProvider最本质的区别,合约事件订阅(web3.eth.subscribe)必须使用 WS 或 IPC Provider;
  • getStatus()on()removeListener()once()removeAllListeners()connect()disconnect()reset()reconnect()全部抛出MethodNotImplementedError(见 src/index.ts)。

test/unit/not_implemented_methods.test.ts 对上述每个方法逐一断言了抛错行为,这可以视为该包的「能力边界契约」:HTTP Provider 只承诺请求-响应式 RPC 调用

六、安装与实战配置指南

6.1 安装

npm install web3-providers-http # 或 yarn add web3-providers-http

详见 README.md。该包是 web3.js 的子包,也可通过顶层 web3 包间接使用(import { HttpProvider } from 'web3')。

6.2 实例化与 providerOptions

HttpProvider构造签名为new HttpProvider(clientUrl, httpProviderOptions?),第二参数类型HttpProviderOptions定义于 src/types.ts:

export interface HttpProviderOptions { providerOptions: RequestInit; }

providerOptions本质是标准RequestInit(fetch 的选项对象)。测试夹具 test/fixtures/test_data.ts 给出了一个非常完整的配置示例,覆盖了绝大多数可用字段:

export const httpProviderOptions = { providerOptions: { body: undefined, cache: 'force-cache', // 强制使用缓存 credentials: 'same-origin', // 同源请求携带凭据 headers: { 'Content-Type': 'application/json' }, integrity: 'foo', keepalive: true, // 允许长连接存活 method: 'GET', // 注意:实际请求中会被强制覆盖为 POST mode: 'same-origin', redirect: 'error', referrer: 'foo', referrerPolicy: 'same-origin', signal: undefined, // 可传入 AbortSignal 实现请求取消 window: undefined, } as RequestInit, };

实战中常用的配置组合包括:

import HttpProvider from 'web3-providers-http'; const provider = new HttpProvider('https://mainnet.infura.io/v3/YOUR_KEY', { providerOptions: { headers: { 'Content-Type': 'application/json', Authorization: 'Bearer YOUR_AUTH_TOKEN', // 私有节点鉴权 }, signal: AbortSignal.timeout(10_000), // 10 秒超时 }, });

6.3 与 Web3 实例集成

由于 web3-core/src/web3_request_manager.ts 默认基于HttpProvider构建请求管理器,HttpProvider既可作为独立 Provider 使用,也可直接注入 web3 实例:

import { Web3 } from 'web3'; import HttpProvider from 'web3-providers-http'; const provider = new HttpProvider('http://localhost:8545'); const web3 = new Web3(provider); // 直接发起 JSON-RPC 调用 const balance = await provider.request({ jsonrpc: '2.0', id: 42, method: 'eth_getBalance', params: ['0x407d73d8a49eeb85d32cf465507dd71d507100c1', 'latest'], });

七、单元测试如何验证这些行为

该包的测试体系为理解其行为契约提供了直接证据:

  • test/unit/implemented_methods.test.ts:通过jest-fetch-mockcross-fetch替换为 mock(jest.setMock('cross-fetch', fetchMock)),验证supportsSubscriptions()返回false、正常响应按原样返回、HTTP 400 时request()reject 且抛出ResponseError
  • test/unit/constructor.test.ts:验证构造时可用providerOptions、合法/非法 URL 的通过/拒绝行为;
  • test/unit/not_implemented_methods.test.ts:逐一验证未实现方法抛MethodNotImplementedError

运行方式(见 package.json 的scripts):

yarn test:unit # 单元测试 yarn test:integration # 集成测试 yarn test:e2e:chrome # 基于 Cypress 的浏览器端 e2e

八、升级到 4.2.0 的检查清单

结合 CHANGELOG 与源码,从 4.0.x 升级到 4.2.0 时建议确认以下几点:

  1. 构建产物路径:4.0.1-alpha.4 起产物目录由dist/变为lib/,若你直接引用包内文件路径需同步更新;
  2. 导入方式:4.0.1-rc.0 起支持import { HttpProvider }命名导入,可摆脱仅默认导出的写法;
  3. Service Worker 支持:需要 SW 环境运行 web3.js 时,请使用 ≥ 4.1.0(cross-fetch v4);
  4. 错误处理:≥ 4.2.0 时ResponseError.statusCode可区分 HTTP 层错误(4xx/5xx),建议在 catch 逻辑中补充状态码分支;
  5. 能力边界:HTTP Provider 不支持订阅与连接生命周期管理,需要事件订阅时切换到 WS/IPC Provider。

结语

web3-providers-http的变更日志记录了一个成熟 Provider 子包的工程化演进:从构建产物结构调整(dist/lib/)、命名导出与混合构建,到网络层升级(cross-fetch v4)与错误信息增强(statusCode)。透过 CHANGELOG 对照 src/index.ts、src/types.ts 与测试用例,可以完整理解其「POST + JSON + 无订阅」的简洁设计,以及它在 web3.js 传输层中所承担的确定性角色。

【免费下载链接】web3.jsCollection of comprehensive TypeScript libraries for Interaction with the Ethereum JSON RPC API and utility functions.项目地址: https://gitcode.com/gh_mirrors/we/web3.js

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询