news 2026/10/17 5:38:38

Service Mocker如何无服务器拦截请求:modern模式Service Worker握手完整原理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Service Mocker如何无服务器拦截请求:modern模式Service Worker握手完整原理

【免费下载链接】service-mocker

🚀 Next generation frontend API mocking framework

项目地址:https://gitcode.com/gh_mirrors/se/service-mocker
点击查看免费下载

在前端开发中,"API mock"(接口模拟)工具往往需要单独搭建一个 mock 服务器:写 JSON、开端口、配代理,流程繁琐。而Service Mocker是一个新一代的前端 API mocking 框架,它借助Service Worker的机制,直接在浏览器内部拦截请求并完成模拟,完全不需要任何真实服务器。本文完整拆解 Service Mocker 在 modern 模式下的 Service Worker 握手原理:客户端如何与服务工作者建立连接,又如何拿到"拦截请求"的权限。🚀

一图看懂整体架构

Service Mocker 的典型用法只有两个文件:

  • server.js(服务器脚本):用 express 风格的路由定义模拟规则,它实际上是被注册为 Service Worker 运行的;
  • app.js(客户端脚本):页面中唯一需要引入的脚本,负责与 Service Worker 完成握手。
// server.js —— 定义模拟规则 import { createServer } from 'service-mocker/server'; const { router } = createServer(); router.get('/greet', (req, res) => { res.send('Hello new world!'); });

握手完成后,页面发起的任何fetch/XMLHttpRequest请求都会被 Service Worker 截获:命中路由规则就返回模拟数据,请求根本不会走到真实网络。这就是"无服务器拦截"的核心。⚡

模式判定:modern 还是 legacy?

Service Mocker 内部有两种工作模式,入口在 src/client/index.js 的createClient()中自动选择:

判定条件结果
浏览器支持 Service Worker(serviceWorker in navigator)继续判定
页面运行在安全环境(HTTPS,或localhost/127.0.0.1)✅ 创建ModernClient(Service Worker 模式)
任一条件不满足⚠️ 控制台警告并降级为LegacyClient(monkey-patch 模式)

另外也支持显式指定:createClient('server.js', { forceLegacy: true })可强制使用 legacy 模式。本文聚焦 modern 模式——这也是 Service Mocker 的"完全体"。

握手第一步:注册 Service Worker

ModernClient初始化时调用 src/client/modern/register.js 中的register(),核心只做两件事:

  1. navigator.serviceWorker.register(scriptURL, { scope: location.pathname })—— 把你的 server.js 注册为 Service Worker,作用域限定在当前页面路径;
  2. 注册成功后立即调用connect()进入握手阶段。

这里有一个容易踩坑的细节:根据浏览器规范,Service Worker 的作用域默认不能超过脚本自身所在路径。如果你的 server.js 放在非根路径(如assets/js/server.js),需要在 dev server 上配置Service-Worker-Allowed响应头来解除限制,详见 docs/caveats.md。

握手核心:connect 与 handshake 逐帧解析

握手逻辑集中在 src/client/modern/connect.js,流程如下:

① 等待 Worker 就绪

先记录hasController(当前页面是否已被某个 Worker 控制),然后await navigator.serviceWorker.ready。注释里写得很清楚:Chrome 在页面重载后有时会"卡住",所有动作都要等 Worker 就绪后再执行。

② 获取(最新)注册

  • 如果页面已有控制器且未跳过更新检查,会走 src/client/modern/get-newest-reg.js 的getNewestReg():执行registration.update()探测新版本,发现新 Worker 后等待其激活(statechange到activated);
  • 否则直接getRegistration()拿到当前注册对象。

③ 发送握手机器码

拿到注册对象后,handshake()执行两跳消息:

顺序消息发送条件作用
1@mocker/request_claim页面尚无控制器(首次安装等"未受控"状态)请求 Worker 立即接管当前页面
2@mocker/ping总是发送探活并确认通道连通,等待@mocker/pong回包

所有动作常量定义在 src/constants/action.js,并统一加上@mocker/前缀以避免与其他页面的消息冲突。握手成功后控制台会打印:

[mocker:modern] connection established

消息是怎么传输的?

消息通道由 src/utils/send-message-request.js 实现:

  • 每次通信创建一个MessageChannel,通过port1/port2成对传递,收到回复后立即关闭端口释放内存;
  • 内置3 秒超时,超时会抛出messaging timeout错误——所以如果握手长时间不完成,通常是 Worker 没有成功加载;
  • 回复中若带error字段则以 reject 抛出,否则 resolve。

可以把它理解成一次轻量级的"TCP 三次握手":请求—应答—确认。

Worker 端的回应:claim 接管是关键

握手的服务端实现非常简洁,就在 src/server/server.js 的事件监听里:

  • 收到PING→ 回一个PONG;
  • 收到REQUEST_CLAIM→ 先执行await self.clients.claim(),再回ESTABLISHED。

为什么要clients.claim()?因为按 Service Worker 默认行为,新安装的 Worker 只会接管之后"新打开"的页面,当前已存在的页面不会被控制。claim()让 Worker 主动接管所有已打开的客户端页面,这正是"无服务器拦截"能够立即生效的前提。

另外两个生命周期细节也值得注意:

self.addEventListener('install', (event) => { event.waitUntil(self.skipWaiting()); // 新版本不排队,直接激活 }); self.addEventListener('activate', (event) => { event.waitUntil(self.clients.claim()); // 激活时接管所有页面 });

skipWaiting()保证路由规则一改就能生效,不用反复强刷;activate里的claim()则确保页面重载后依然处于受控状态。

握手完成后:请求是如何被拦截的

握手的意义在于"拿到控制权和确认连通性",真正的拦截发生在 Service Worker 的fetch事件上。同样在 src/server/server.js 中:

self.addEventListener('fetch', (event) => { MockerRouter.routers.some((router) => { return router._match(event); // 逐个路由表尝试匹配 }); });

匹配逻辑在 src/server/router.js 的_match()中,依次校验:

  1. 请求 origin 与路由所属 origin 一致;
  2. 去掉 baseURL 前缀后,路径命中path-to-regexp规则;
  3. HTTP 方法匹配(或注册了all)。

命中后同步构造MockerRequest和MockerResponse,先跑完所有中间件,再执行你写的回调(res.send(...)/res.json(...)等)。由于这一切都发生在 Service Worker 上下文内,返回的仍是标准Response对象——在浏览器 Network 面板里能看到"真实"的请求与响应头,调试体验与真接口几乎无差别。✅

容易忽略的三个细节

  • client.ready之前,任何请求都不会被拦截。这是官方文档(docs/api.md)明确强调的:所有初始化代码应放进client.ready.then(...)里执行,否则页面启动早期的请求会直接打到真实网络;
  • Worker 更新自动重连:src/client/modern/client.js 的_autoSyncClient()监听controllerchange事件,Worker 升级后自动与新 Worker 重新握手(此时跳过更新检查),并在控制台提示 "mocker updated, reload your requests to take effect";
  • 同一端口多项目会互相干扰:因为 Worker 按 origin + scope 拦截请求,切换到一个没有 mock 的项目时可能被"误拦截",此时可调用client.unregister()或到浏览器开发者工具中手动注销 Worker,详见 docs/caveats.md。

快速上手清单 📋

  1. 安装(仅开发依赖即可):npm install service-mocker --save-dev;
  2. 编写 server.js 定义路由(参考上文示例,完整 API 见 docs/api.md);
  3. 页面中仅引入客户端脚本,createClient('server.js')后在client.ready.then(...)中发请求;
  4. 用http://localhost:3000这类本地地址打开页面(localhost 免 HTTPS,满足安全环境要求);
  5. 看到控制台输出[mocker:modern] connection established,说明 Service Worker 握手成功,拦截已就绪。

写在最后

Service Mocker 的 modern 模式用一次"Service Worker 握手"替代了传统 mock 方案里整个服务器:register注册、claim接管、PING/PONG确认、fetch事件拦截——每一步都依托浏览器原生能力,零依赖、零端口、零代理。理解这套握手流程后,你就能准确判断 mock 为何"没生效":是没握手成功(等ready)、是作用域限制(scope 路径问题),还是 Worker 被残留的旧注册占用(unregister 即可)。🎉

更多使用细节可以查看仓库内的 README.md 与 docs/api.md。

【免费下载链接】service-mocker

🚀 Next generation frontend API mocking framework

项目地址:https://gitcode.com/gh_mirrors/se/service-mocker
点击查看免费下载

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/17 5:37:36

Altium Designer封装库全解析:三层数据、建库流程与避坑

简介:一套面向电子工程师与PCB设计初学者的Altium Designer封装库合集,覆盖常用元器件封装,同时提供原理图符号、PCB封装与3D模型,解决设计过程中封装不全、匹配困难的问题。资源共245个文件,包括89个PcbLib封装库、55…

作者头像 李华
网站建设 2026/10/17 5:37:09

GitHub_Trending/templa/templates高级自动化技巧:条件判断与循环执行

GitHub_Trending/templa/templates高级自动化技巧:条件判断与循环执行 GitHub_Trending/templa/templates是基于开源新版QD框架站发布的公共har模板库,提供了丰富的自动化任务模板,帮助用户轻松实现各类网站的签到、数据抓取等自动化操作。本…

作者头像 李华
网站建设 2026/10/17 5:36:04

SQL Server迁移MySQL实战:结构转换、存储过程改写与性能调优指南

1. 迁移前必须先想清楚的几件事在拿到"SQL Server 迁移到 MySQL"这个任务时,先别急着开工具导数据。我见过太多人第一步就栽在评估上——误以为两边都是关系型数据库,表结构导过去、数据灌进去就算完事,结果上线当晚存储过程全部报…

作者头像 李华
网站建设 2026/10/17 5:35:36

PostgreSQL分区表实战:破解单表亿级数据查询性能瓶颈

单表破亿,查询慢到报警,这场景我在不止一个项目里见过。最开始可能只是运营那边发一句“报表跑不出来了”,后来越来越频繁,慢查询日志里全是那张表,数据库CPU居高不下,磁盘IO一直打满,索引加了几…

作者头像 李华
网站建设 2026/10/17 5:35:16

88E6321交换机参考设计实战:从原理图到量产的关键设计要点

简介:这份资源是Marvell CoverLink Street 88E6321交换机的官方参考设计资料,面向从事千兆以太网交换机硬件设计、嵌入式网络开发及音视频传输系统集成的工程师。88E6321为7端口千兆AVB交换机,集成2个PHY并支持Energy Efficient Ethernet节能…

作者头像 李华