ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

用 Miniflare 本地测试 Cloudflare Workers 中的 WebSockets:从 Echo 服务器到 dispatchFetch 客户端

用 Miniflare 本地测试 Cloudflare Workers 中的 WebSockets:从 Echo 服务器到 dispatchFetch 客户端 用 Miniflare 本地测试 Cloudflare Workers 中的 WebSockets从 Echo 服务器到 dispatchFetch 客户端【免费下载链接】cloudflare-docsCloudflare’s documentation项目地址: https://gitcode.com/GitHub_Trending/cl/cloudflare-docsMiniflare 是 Cloudflare 官方提供的 Workers 本地模拟器它会自动处理 WebSocket 协议升级让你无需真实浏览器或网络即可在 Node.js 环境中对 Worker 内的 WebSocket 服务器与客户端进行端到端测试。本文以 WebSockets 文档为主线完整讲解如何在 Miniflare 中实现一个 Echo WebSocket 服务器并通过dispatchFetch拿到Response.webSocket完成消息回环断言同时结合 Workers 运行时 API 参考补齐WebSocketPair、close 帧行为等关键细节使测试真正可复制、可运行。1. 背景Miniflare 与 Workers 的 WebSocket 测试Miniflare 用 TypeScript 编写把 Worker 代码放进一个实现了 Workers 运行时 API 的沙箱中运行支持 KV、Durable Objects、WebSockets、modules 等特性且完全本地运行、无需联网。对于大多数用户官方建议先用 Wrangler 做本地开发只有需要低层模拟器控制如直接派发事件、精细断言响应时才直接使用 Miniflare API。在 WebSocket 场景中Miniflare 有一个关键行为它总会升级 WebSocket 连接。也就是说你不需要像浏览器那样自己完成 HTTP 握手你的职责只有一个——让 Worker 返回一个状态码为101 Switching Protocols且携带webSocket属性的Response。整个测试链路因此简化为两条路径服务器侧Worker 的fetch处理器创建WebSocketPairaccept()服务器端把客户端端挂到Response上客户端侧测试代码用mf.dispatchFetch()发起带Upgrade: websocket头的请求从返回的Response上取出res.webSocket同样accept()后收发消息。2. 服务器端实现一个 Echo WebSocket 服务器原文档给出的最简可运行示例如下。Worker 收到请求后创建一对 WebSocket接受服务器端并注册message监听器做回显最后把客户端端放进101响应返回export default { fetch(request) { const [client, server] Object.values(new WebSocketPair()); server.accept(); server.addEventListener(message, (event) { server.send(event.data); }); return new Response(null, { status: 101, webSocket: client, }); }, };这段代码涉及的运行时语义可以对照 WebSockets Reference 逐项理解new WebSocketPair()返回一个对象键0和1各持有一个WebSocket实例即{ 0: WebSocket, 1: WebSocket }。惯例上用Object.values加 ES6 解构把两端取出分别命名为client与server。server.accept()接受连接使运行时开始处理该 WebSocket 上的数据流。accept()可传入可选配置对象其中allowHalfOpen默认false控制收到对端 Close 帧时是否自动回复对等的 Close 帧——设为true时readyState会保持CLOSING直到你显式调用close()适用于 WebSocket 代理这类需要在两侧独立协调关闭的场景。addEventListener(message, ...)message事件在收到新消息时触发事件对象含data对端发来的数据与type默认message。除了message运行时还定义了close携带CloseEvent的code、reason、wasClean属性和error事件。server.send(event.data)向该 WebSocket 对中的另一端发送消息参数可以是字符串或可转为字符串的类型对象和数组应先JSON.stringify。new Response(null, { status: 101, webSocket: client })状态码101表示协议切换成功webSocket属性把client端交给传输层。一个与 官方示例文档 一致的习惯做法是在创建WebSocketPair前先用request.headers.get(Upgrade)检查请求头是否为websocket不匹配时返回426错误响应避免把普通 HTTP 请求误当作 WebSocket 握手处理。另外需要注意消息大小的运行时限制Worker 收到的 WebSocket 消息上限为32 MiB33,554,432 字节超限的连接会被自动以1009 Message is too large关闭。写回显或大数据量测试用例时应把这一点考虑进断言。3. 客户端用 dispatchFetch 驱动 WebSocket 测试当通过 Miniflare API 的dispatchFetch向 Worker 派发请求时连接升级由 Miniflare 自动完成但你负责处理Response上的webSocket属性。假设上面那段 Worker 脚本存放在echo.mjs中测试脚本可以这样组织此代码完整继承自 原文档import { Miniflare } from miniflare; const mf new Miniflare({ modules: true, scriptPath: echo.mjs, }); const res await mf.dispatchFetch(https://example.com, { headers: { Upgrade: websocket, }, }); const webSocket res.webSocket; webSocket.accept(); webSocket.addEventListener(message, (event) { console.log(event.data); }); webSocket.send(Hello!); // Above listener logs Hello!逐步拆解这个客户端流程new Miniflare({ modules: true, scriptPath: echo.mjs })以 ES Modules 模式加载echo.mjs。Miniflare 构造函数中script与scriptPath至少提供一个——前者内联字符串脚本后者指向文件。也可以改用modules: [{ type: ESModule, path: ... }]显式列出模块或用scriptPathmodules: truemodulesRules让 Miniflare 自动爬取模块图参考 Get Started 与 Writing tests。mf.dispatchFetch(https://example.com, { headers: { Upgrade: websocket } })dispatchFetch的 API 与标准fetch一致接受 URL RequestInit或Request对象。这里不需要真实可达的https://example.com——请求被直接派发到本地 Worker。Miniflare 会自动升级连接返回的res状态即101。res.webSocket握手成功后Response对象上带有webSocket属性这就是与 Worker 内client端配对的客户端端语义与 Worker 里用fetch拿Upgrade连接得到的resp.webSocket完全相同。webSocket.accept()表明你在测试侧接管这个 socket而不是把它继续转发出去。send(Hello!)触发回环Worker 的message监听器调用server.send(event.data)消息原样发回测试侧的message监听器打印Hello!。在断言框架中可以改为把event.data存入变量或Deferred中等待再断言其等于发送的内容。dispatchFetch的其他通用能力同样适用于 WebSocket 测试场景派发fetch事件时由你自己补充CF-*头与cf对象来控制测试输入Miniflare 还会按序调用每个fetch监听器直到产生响应。详见 Fetch Events。4. 把 WebSocket 测试放进 node:testWriting tests 演示了用 Node.js 内置node:test框架组织 Miniflare 测试的标准骨架在before钩子里创建实例并await worker.ready在after钩子里dispose()清理测试本体通过dispatchFetch断言响应。按该骨架可以写出一个可直接运行的 WebSocket 回环测试import assert from node:assert; import test, { after, before, describe } from node:test; import { Miniflare } from miniflare; describe(echo websocket worker, () { /** type {Miniflare} */ let mf; before(async () { mf new Miniflare({ modules: [ { type: ESModule, path: src/echo.mjs, // 第 2 节中的 echo 服务器脚本 }, ], }); await mf.ready; }); after(async () { await mf.dispose(); }); test(echoes messages back, async () { const res await mf.dispatchFetch(https://example.com, { headers: { Upgrade: websocket }, }); assert.strictEqual(res.status, 101); const ws res.webSocket; assert.ok(ws); const received new Promise((resolve) { ws.addEventListener(message, (event) resolve(event.data)); }); ws.accept(); ws.send(Hello!); assert.strictEqual(await received, Hello!); }); });运行方式为node --test。两个值得注意的实现事实均来自该文档Miniflare 不读取 Wrangler 配置文件Worker 用到的所有 bindings 必须在 Miniflare 选项里显式声明使用 Miniflare 时只有 Worker 本身运行在workerd中测试文件运行在 Node.js 中。所有对 Worker 的访问都必须经由dispatchFetch这类 Miniflare API无法像 Vitest 集成那样直接单元测试 Worker 内的函数。5. close 帧行为与二进制消息影响断言写法的运行时细节写 WebSocket 断言前建议了解两个会直接影响message/close事件形态的运行时行为详见 WebSockets Referenceclose 帧自动回复。在web_socket_auto_reply_to_close兼容性标志2026-04-07及之后的兼容性日期默认启用下Worker 收到对端 Close 帧时会自动回复对等的 Close 帧且readyState在close事件触发前已过渡到CLOSED在close事件处理器里再调close()会被静默忽略。需要半开half-open行为的代理场景应改用server.accept({ allowHalfOpen: true })此时收到 Close 帧后readyState保持CLOSING由你的代码择机调用server.close(event.code, done)完成握手。若兼容性日期早于该阈值或使用web_socket_manual_reply_to_close标志则收到 Close 帧后必须手动调用close()否则客户端可能收到1006异常关闭错误。二进制消息的交付类型。帧是文本还是二进制由发送方决定文本帧始终以字符串交付。二进制帧则按 socket 的binaryType交付为Blob或ArrayBuffer在websocket_standard_binary_type兼容性标志2026-03-17及之后的日期默认启用下默认是Blob读取字节需要异步await event.data.arrayBuffer()未启用时默认是ArrayBuffer可用new Uint8Array(event.data)同步读取。binaryType是可变属性运行时在每次分发二进制帧时才读取它的当前值因此若要让整个连接的行为一致应在accept()之前赋值。这些行为在 Miniflare 中同样成立意味着测试用例对event.data的类型断言typeof还是instanceof Blob应与你的兼容性日期保持一致。6. 小结与延伸阅读Miniflare 自动处理 WebSocket 升级测试者只需关心两端Worker 返回101 webSocket的Response测试代码经dispatchFetch拿res.webSocket完成accept()与收发完整的 echo 服务器与dispatchFetch客户端代码已在第 2、3 节给出可按node --test骨架组装成可重复运行的回归测试消息上限 32 MiB、close 自动回复、binaryType交付类型等运行时规则会直接影响断言编写用例前应先确认兼容性日期。延伸阅读均为本仓库内文档WebSocketsMiniflare Core 原文档WebSockets ReferenceUsing the WebSockets API含浏览器客户端与 fetch 客户端写法Miniflare Get Started完整 API 参考Fetch EventsWriting tests【免费下载链接】cloudflare-docsCloudflare’s documentation项目地址: https://gitcode.com/GitHub_Trending/cl/cloudflare-docs创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表