Miniflare Web Standards 支持与出站 fetch 请求 Mock 实战指南 Miniflare Web Standards 支持与出站 fetch 请求 Mock 实战指南【免费下载链接】cloudflare-docsCloudflare’s documentation项目地址: https://gitcode.com/GitHub_Trending/cl/cloudflare-docs本文围绕 Cloudflare 官方文档仓库中 Miniflare Web Standards 参考页 展开讲解在本地模拟器 Miniflare 中如何运行符合 Web 标准的 Workers 代码如何使用 undici 的MockAgent完整接管并 Mock Worker 的所有出站fetch()请求以及 Miniflare 与生产环境在 subrequests 限制上的关键差异帮助你在不依赖网络和生产账号的前提下编写可离线运行、结果可复现的 Worker 测试。1. Miniflare 与 Web Standards 的关系Miniflare 是用于本地开发、调试和测试 Cloudflare Workers 的模拟器它以 TypeScript 编写将你的 Worker 代码放入一个实现了 Workers 运行时 API 的沙箱中执行因此可以完全离线运行。它的定位在 Miniflare 索引页 中有明确说明——该文档描述的是 Miniflare API主要面向高级使用场景日常本地开发通常通过 Wrangler 完成。Miniflare 沙箱中可用的运行时能力与生产 Workers 运行时的 Web 标准支持保持一致。Web Standards 参考页 开篇即列出了一组指向运行时 API 参考的入口覆盖以下主题Web Standards 总览EncodingTextEncoder/TextDecoder等Fetch APIRequest / ResponseStreamsWeb Crypto其中 Web Standards 总览文档 web-standards.mdx 给出了生产运行时的完整能力清单这些能力同样是你在 Miniflare 中编写和验证代码时的基准JavaScript 标准运行时构建在 V8 引擎之上至少与当前 Chrome 稳定版使用的 V8 版本同步更新标准内置对象基本全量可用例外是出于安全考虑禁用了eval()、new Function、WebAssembly.compile、WebAssembly.compileStreaming、带 buffer 参数的WebAssembly.instantiate和WebAssembly.instantiateStreaming。Worker Global Scope APIatob()/btoa()、定时器setInterval、setTimeout等仅在 Request Context 内可用、performance.timeOrigin与performance.now()、EventTarget/Event、AbortController/AbortSignal以及仅在 Request Context 内可用的fetch()。时间语义的特殊性Date.now()返回的是最近一次 I/O 的时间代码执行期间不会前进performance.timeOrigin恒为0且performance.now()有意降低了精度因此在 Workers 中performance.now()始终等于Date.now()这是写时间相关断言时必须了解的运行时约束。其他全局 APIURL API默认行为与 URL Spec 存在差异可通过url_standard兼容性标志启用规范实现、Compression Streamsdeflate / deflate-raw / gzip、URLPattern、Intl以及通过兼容性标志开启的navigator.userAgent固定值Cloudflare-Workers、navigator.sendBeacon()和 Web File System Access APIenable_web_file_system标志。在 Miniflare 中验证这些行为时可结合 Compatibility Dates 文档 使用compatibilityDate和compatibilityFlags选项使沙箱与生产运行时的行为在特定兼容性日期/标志下对齐const mf new Miniflare({ compatibilityDate: 2021-11-12, compatibilityFlags: [ formdata_parser_supports_files, durable_object_fetch_allows_relative_url, ], });需要注意的是若不显式设置compatibilityDateMiniflare 会默认取一个相当早的时间点这可能使你的测试与生产行为不一致。2. Mock 出站fetch请求这是 standards.md 的核心实操内容。当 Worker 需要请求其他服务第三方 API、内部微服务等时直接发起真实网络请求会让测试变得不稳定且依赖外部环境。Miniflare 通过 undici 的MockAgentAPI 解决了这个问题你可以为特定请求注入自定义Response从而完全替代真实的fetch()调用。2.1 启用方式createFetchMock()与fetchMock选项启用 fetch Mock 的步骤分三步使用createFetchMock()创建一个MockAgent将该对象作为fetchMock选项传入Miniflare构造函数将其与实例关联在测试中对该MockAgent注册拦截规则并配置回复。官方文档给出的完整示例如下import { Miniflare, createFetchMock } from miniflare; // Create MockAgent and connect it to the Miniflare instance const fetchMock createFetchMock(); const mf new Miniflare({ modules: true, script: export default { async fetch(request, env, ctx) { const res await fetch(https://example.com/thing); const text await res.text(); return new Response(\response:\${text}\); } } , fetchMock, }); // Throw when no matching mocked request is found fetchMock.disableNetConnect(); // Mock request to https://example.com/thing const origin fetchMock.get(https://example.com); origin .intercept({ method: GET, path: /thing }) .reply(200, Mocked response!); const res await mf.dispatchFetch(http://localhost:8787/); console.log(await res.text()); // response:Mocked response!执行流程可以拆解为new Miniflare(...)构造沙箱并把fetchMock注入到其 fetch 实现中Worker 脚本内对https://example.com/thing的fetch()被拦截并命中intercept({ method: GET, path: /thing })规则返回状态码 200、正文为Mocked response!的响应外层再通过dispatchFetch(http://localhost:8787/)向 Worker 派发请求最终打印response:Mocked response!。2.2 关键方法与行为说明方法 / 选项作用createFetchMock()创建一个 undiciMockAgent实例用于替代真实 fetchfetchMock选项将MockAgent与Miniflare实例关联使其接管实例内所有出站fetch()fetchMock.disableNetConnect()禁用真实网络连接当请求没有命中任何拦截规则时直接抛错而非放行到网络。这是测试隔离的保险丝防止 Mock 遗漏导致测试意外访问外部服务fetchMock.get(origin)获取指定源站如https://example.com的MockPool在其上注册拦截规则origin.intercept(options)声明要拦截的请求options可包含method、path等匹配条件.reply(status, body)为命中规则请求返回指定状态码与响应体这里disableNetConnect()的语义值得强调undici 的MockAgent默认在找不到匹配规则时会回退到真实网络连接。在自动化测试中这种回退是危险的——它会引入不可复现的外部依赖。因此官方示例在构造Miniflare后第一件事就是调用fetchMock.disableNetConnect()把未声明的外部请求变成显式失败。2.3 与 Miniflare 其余选项的配合fetchMock是Miniflare构造器众多选项之一。参照 Get Started 参考 给出的完整选项面fetch Mock 可以自然地与其他本地模拟能力组合kvNamespacesKV 模拟、r2BucketsR2 模拟、durableObjectsDurable Objects 模拟、cachesCache 模拟等。这意味着一个典型的离线测试环境是出站 HTTP 由fetchMock拦截、存储由本地模拟、事件通过dispatchFetch和getWorker()派发整个测试不触网、可重复。测试结束时应调用await mf.dispose()释放 HTTP 服务器与存储连接。3. SubrequestsMiniflare 不限制生产环境有限额standards.md 的最后一节指出一个测试与生产的差异Miniflare 不支持限制 subrequests子请求数量。生产 Workers 平台对每个账户计划规定了 subrequests 上限参见 Limits 文档而 Miniflare 不会模拟这一配额约束。实际含义是如果你的 Worker 在生产环境会因 subrequests 超限而失败本地 Miniflare 测试可能完全无法暴露该问题。编写此类测试时应当在本地统计 Worker 单次请求生命周期内发起的出站请求次数并在测试断言中与生产配额对比若 Worker 的出站请求来自循环或递归逻辑重点评审其最坏路径下的请求量结合fetchMock.disableNetConnect()先确认所有出站请求都被声明并 Mock再评估数量是否合理。这属于模拟器的已知边界类知识Miniflare 追求的是 API 行为的高保真而配额类平台约束不在模拟范围内。4. 替代方案Vitest 集成下的出站请求 Mock如果你使用的不是 Miniflare API而是cloudflare/vitest-plugin则仓库文档推荐的 Mock 方案是msw/cloudflareMSW而非 undiciMockAgent。两者定位相同——拦截 Worker 的出站 HTTP该集成还支持 WebSocket——但 API 形态不同import { setupNetwork } from msw/cloudflare; export const network setupNetwork();在 Vitest setup 文件中调用network.enable()/network.resetHandlers()/network.disable()管理生命周期然后通过 MSW 的http.get(...)handler 声明拦截规则network.use( http.get(https://api.example.com/greeting, () { return HttpResponse.json({ message: Hello }); }), );选择建议直接以编程方式使用Miniflare类如构建自定义测试工具、需要与 KV/R2/DO 本地模拟深度集成时使用本文第 2 节的createFetchMock()方案项目已接入 Vitest 官方插件时使用 MSW 方案即可覆盖出站 HTTP 与 WebSocket Mock。5. 小结围绕 standards.md 这份参考文档本文梳理了 Miniflare 在 Web 标准维度上的三条主线标准能力对齐Miniflare 沙箱遵循生产运行时的 Web 标准支持V8 引擎、Worker Global Scope API、Encoding、URL、Compression Streams、Web Crypto 等可用compatibilityDate/compatibilityFlags进一步对齐行为出站请求 Mock通过createFetchMock()创建 undiciMockAgent、经fetchMock选项接入 Miniflare配合disableNetConnect()、get(origin)、intercept()、reply()实现完全离线的 HTTP 测试已知差异Miniflare 不模拟生产环境的 subrequests 配额涉及大量出站请求的 Worker 需要在测试中自行校验请求数量。以上结论与代码均来自本仓库文档standards.md、Miniflare 索引、Get Started、Compatibility Dates 与 Workers Web Standards 参考可据此深入查阅。【免费下载链接】cloudflare-docsCloudflare’s documentation项目地址: https://gitcode.com/GitHub_Trending/cl/cloudflare-docs创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考