buse-sw-mock
v1.0.5
Published
基于 ServiceWorker 的强大 API 模拟系统,支持网络故障仿真
Downloads
50
Maintainers
Readme
SwMock 完整集成指南
🚀 buse-sw-mock - 基于ServiceWorker的前端API模拟解决方案 版本:v1.0.4 | 更新时间:2024-07-30
📋 目录导航
🚀 快速开始
5分钟快速集成
1. 安装依赖
# 使用 npm
npm install @buse/sw-mock
# 使用 yarn
yarn add @buse/sw-mock
# 使用 pnpm
pnpm add @buse/sw-mock2. 快速测试(推荐)
安装完成后,可以立即启动测试服务验证功能:
# 启动测试服务器
npx swmock-test
# 或自动打开浏览器
npx swmock-test --open
# 访问测试页面
# http://localhost:3000/swmock-test-page.html💡 提示: 测试服务提供了完整的SwMock功能验证,包括API拦截测试、配置对比等功能。
3. 复制ServiceWorker文件
将 sw-mock-worker.js 文件复制到项目的 public 目录:
# 从 node_modules 复制
cp node_modules/buse-sw-mock/dist/sw-mock-worker.js public/4. 创建Mock数据
在 public/mock/ 目录下创建API模拟数据:
mkdir -p public/mock/api/users创建 public/mock/api/users/list.json:
{
"code": "00000",
"msg": "获取成功",
"data": {
"list": [
{"id": 1, "name": "张三", "email": "[email protected]"},
{"id": 2, "name": "李四", "email": "[email protected]"}
],
"total": 2
}
}5. 初始化SwMock
import { createSwMock } from 'buse-sw-mock';
const swMock = createSwMock();
// 初始化
await swMock.init({
enabled: true,
debug: true,
workerUrl: '/sw-mock-worker.js'
});
// 启用模拟
await swMock.enable();
console.log('SwMock 已启用!');5. 测试API调用
// 这个请求将被SwMock拦截并返回模拟数据
const response = await fetch('/api/users/list');
const data = await response.json();
console.log(data); // 返回模拟数据🎉 恭喜! 您已经成功集成了SwMock。接下来可以探索更多高级功能。
✨ 核心功能
🎯 三大核心特性
1. 自定义Mock文件存放路径配置
- 功能:通过
mockDataPath配置项自定义mock文件存放位置 - 默认值:
/mock - 优势:灵活适配不同项目结构,避免路径冲突
2. 嵌套目录结构支持
- 功能:支持按URL路径创建嵌套的目录结构
- 智能回退:嵌套结构 → 扁平结构 → 真实服务器
- 优势:更直观的文件组织,便于维护大型项目
3. ServiceWorker Scope配置支持
- 功能:通过
scope配置项控制ServiceWorker作用域 - 默认值:
/(全站拦截) - 优势:精确控制拦截范围,适配微前端架构
🛠️ 其他强大功能
- 多响应配置:同一接口根据不同参数返回不同响应
- 智能参数匹配:支持query参数、请求体、请求头等多种匹配方式
- 权重优先级系统:高权重响应优先匹配,智能回退机制
- 网络故障模拟:模拟各种网络异常情况
- 实时配置更新:运行时动态修改配置
- 请求拦截控制:灵活的拦截和排除规则
- 调试模式:详细的日志输出和状态监控
- 事件系统:完整的生命周期事件
- 插件系统:可扩展的插件架构
📦 安装配置
环境要求
- 浏览器支持:支持ServiceWorker的现代浏览器
- Node.js:≥ 14.0.0(开发环境)
- TypeScript:≥ 4.0.0(可选,推荐)
安装方式
NPM 安装
npm install buse-sw-mock --save-devCDN 引入
<!-- ES Module -->
<script type="module">
import { createSwMock } from 'https://unpkg.com/buse-sw-mock/dist/index.esm.js';
</script>
<!-- UMD -->
<script src="https://unpkg.com/buse-sw-mock/dist/index.umd.js"></script>项目结构设置
推荐的项目结构:
your-project/
├── public/
│ ├── sw-mock-worker.js # ServiceWorker文件
│ └── mock/ # Mock数据目录(可自定义)
│ ├── api/ # API相关mock数据
│ │ ├── users/
│ │ │ ├── list.json
│ │ │ ├── detail.json
│ │ │ └── create.json
│ │ └── orders/
│ │ ├── list.json
│ │ └── create.json
│ └── service/
│ └── config.json
├── src/
│ └── main.js # 应用入口文件
└── package.json
📚 API参考
核心API
createSwMock()
创建SwMock实例。
import { createSwMock } from 'buse-sw-mock';
const swMock = createSwMock();init(options?: SwMockInitOptions)
初始化SwMock实例。
await swMock.init({
enabled: true,
debug: false,
workerUrl: '/sw-mock-worker.js',
mockDataPath: '/mock',
scope: '/',
interceptPatterns: ['/api/'],
excludePatterns: ['.js', '.css', '.png'],
autoRegister: true
});参数类型:
interface SwMockInitOptions {
enabled?: boolean; // 是否启用模拟,默认 false
debug?: boolean; // 调试模式,默认 false
workerUrl?: string; // ServiceWorker文件URL,默认 '/sw-mock-worker.js'
mockDataPath?: string; // Mock数据路径,默认 '/mock'
scope?: string; // ServiceWorker作用域,默认 '/'
interceptPatterns?: string[]; // 拦截模式,默认 ['/api/']
excludePatterns?: string[]; // 排除模式
autoRegister?: boolean; // 自动注册ServiceWorker,默认 true
networkFailure?: Partial<NetworkFailureConfig>; // 网络故障配置
}enable()
启用API模拟。
await swMock.enable();disable()
禁用API模拟。
await swMock.disable();toggle()
切换API模拟状态。
await swMock.toggle();getStatus()
获取当前状态信息。
const status = await swMock.getStatus();
console.log(status);返回类型:
interface SwMockStatus {
enabled: boolean; // 是否已启用
debug: boolean; // 调试模式状态
defaultDelay: number; // 默认延迟时间
globalDelay: number | null; // 全局延迟时间
interceptPatterns: string[]; // 拦截模式列表
excludePatterns: string[]; // 排除模式列表
endpointsCount: number; // 端点数量
serviceWorkerReady: boolean; // ServiceWorker就绪状态
mockDataPath: string; // Mock数据路径
scope: string; // ServiceWorker作用域
networkFailure: { // 网络故障状态
enabled: boolean;
httpErrors: boolean;
timeout: boolean;
connectionFailure: boolean;
responseDelay: boolean;
intermittentFailure: boolean;
};
}updateConfig(config: Partial)
更新配置。
await swMock.updateConfig({
debug: true,
defaultDelay: 1000,
mockDataPath: '/custom-mock'
});resetConfig()
重置配置为默认值。
await swMock.resetConfig();网络故障模拟API
enableNetworkFailure(config?: Partial)
启用网络故障模拟。
await swMock.enableNetworkFailure({
scenarios: {
httpErrors: {
enabled: true,
statusCodes: [500, 502, 503],
rate: 0.1
}
}
});disableNetworkFailure()
禁用网络故障模拟。
await swMock.disableNetworkFailure();事件系统API
on(event: string, listener: Function)
监听事件。
swMock.on('enabled', () => {
console.log('SwMock已启用');
});
swMock.on('disabled', () => {
console.log('SwMock已禁用');
});
swMock.on('error', (error) => {
console.error('SwMock错误:', error);
});off(event: string, listener?: Function)
移除事件监听器。
swMock.off('enabled');
swMock.off('error', errorHandler);插件系统API
use(plugin: SwMockPlugin)
安装插件。
const myPlugin = {
name: 'my-plugin',
install(swMock) {
// 插件逻辑
}
};
swMock.use(myPlugin);
⚙️ 配置选项
基础配置
mockDataPath - Mock数据路径
类型:string
默认值:'/mock'
描述:指定mock数据文件的存放目录
// 使用默认路径
await swMock.init({
mockDataPath: '/mock' // 默认值
});
// 使用自定义路径
await swMock.init({
mockDataPath: '/api-mock'
});
// 使用相对路径
await swMock.init({
mockDataPath: 'custom-mock' // 会转换为 '/custom-mock'
});路径规则:
- 支持绝对路径:
/mock、/data/mock - 支持相对路径:
mock、data/mock(自动转换为绝对路径) - 路径会自动标准化(确保以
/开头,不以/结尾)
scope - ServiceWorker作用域
类型:string
默认值:'/'
描述:控制ServiceWorker能够拦截的请求范围
// 全站拦截(默认)
await swMock.init({
scope: '/'
});
// 只拦截API请求
await swMock.init({
scope: '/api/'
});
// 微前端应用隔离
await swMock.init({
scope: '/my-app/',
workerUrl: '/my-app/sw-mock-worker.js'
});重要注意事项:
- ServiceWorker的scope不能超出其脚本文件所在的路径
- 如果workerUrl是
/sw-mock-worker.js,scope可以是/或其子路径 - 如果workerUrl是
/app/sw-mock-worker.js,scope只能是/app/或其子路径
interceptPatterns - 拦截模式
类型:string[]
默认值:['/api/']
描述:定义需要拦截的URL模式
await swMock.init({
interceptPatterns: [
'/api/', // 拦截所有 /api/ 开头的请求
'/service/', // 拦截所有 /service/ 开头的请求
'microgrids-service', // 拦截包含此字符串的请求
'/v1/users' // 拦截特定路径
]
});excludePatterns - 排除模式
类型:string[]
默认值:静态资源文件扩展名
描述:定义需要排除拦截的URL模式
await swMock.init({
excludePatterns: [
'/sw-mock-worker.js', // 排除ServiceWorker文件
'/mock/', // 排除mock数据文件
'.js', '.css', // 排除JavaScript和CSS文件
'.png', '.jpg', // 排除图片文件
'.woff', '.ttf', // 排除字体文件
'/health-check' // 排除健康检查接口
]
});高级配置
networkFailure - 网络故障模拟
类型:NetworkFailureConfig
描述:配置各种网络故障模拟场景
await swMock.init({
networkFailure: {
enabled: true,
scenarios: {
// HTTP错误模拟
httpErrors: {
enabled: true,
statusCodes: [400, 401, 403, 404, 500, 502, 503, 504],
rate: 0.1, // 10%的请求返回错误
distribution: 'random' // 随机分布
},
// 超时模拟
timeout: {
enabled: true,
duration: 30000, // 30秒超时
rate: 0.05 // 5%的请求超时
},
// 连接失败模拟
connectionFailure: {
enabled: true,
rate: 0.02 // 2%的请求连接失败
},
// 响应延迟模拟
responseDelay: {
enabled: true,
minDelay: 1000, // 最小延迟1秒
maxDelay: 5000, // 最大延迟5秒
rate: 0.3 // 30%的请求有额外延迟
},
// 间歇性故障模拟
intermittentFailure: {
enabled: true,
failureDuration: 10000, // 故障持续10秒
recoveryDuration: 30000, // 恢复持续30秒
rate: 0.1 // 10%概率触发间歇性故障
}
}
}
});完整配置示例
const swMock = createSwMock();
await swMock.init({
// 基础配置
enabled: true,
debug: true,
workerUrl: '/sw-mock-worker.js',
autoRegister: true,
// 路径配置
mockDataPath: '/custom-mock',
scope: '/api/',
// 拦截配置
interceptPatterns: ['/api/', '/service/', '/v1/'],
excludePatterns: ['.js', '.css', '.png', '.jpg'],
// 延迟配置
defaultDelay: 500,
globalDelay: null,
// 错误配置
errorRate: 0.05,
// 网络故障配置
networkFailure: {
enabled: false,
scenarios: {
httpErrors: {
enabled: false,
statusCodes: [500, 502, 503],
rate: 0.1,
distribution: 'random'
}
}
}
});📁 目录结构
支持的目录结构
SwMock支持两种目录结构模式,并提供智能回退机制:
1. 嵌套目录结构(推荐)
按照URL路径结构创建嵌套的目录,更直观地组织模拟数据:
public/mock/ # mockDataPath 配置的路径
├── api/
│ ├── users/
│ │ ├── list.json # GET /api/users/list
│ │ ├── detail.json # GET /api/users/detail
│ │ ├── create.json # POST /api/users/create
│ │ └── update.json # PUT /api/users/update
│ ├── orders/
│ │ ├── list.json # GET /api/orders/list
│ │ ├── detail.json # GET /api/orders/detail
│ │ └── create.json # POST /api/orders/create
│ └── products/
│ ├── categories.json # GET /api/products/categories
│ └── search.json # GET /api/products/search
├── service/
│ ├── config.json # GET /service/config
│ └── status.json # GET /service/status
└── v1/
└── auth/
├── login.json # POST /v1/auth/login
└── logout.json # POST /v1/auth/logout2. 扁平化结构(兼容旧版本)
使用下划线替代斜杠的扁平化文件命名:
public/mock/
├── api_users_list.json # GET /api/users/list
├── api_users_detail.json # GET /api/users/detail
├── api_users_create.json # POST /api/users/create
├── api_orders_list.json # GET /api/orders/list
├── api_orders_create.json # POST /api/orders/create
├── service_config.json # GET /service/config
├── v1_auth_login.json # POST /v1/auth/login
└── v1_auth_logout.json # POST /v1/auth/logout路径映射规则
| URL路径 | 嵌套结构路径 | 扁平结构路径 | 说明 |
|---------|-------------|-------------|------|
| /api/users/list | /mock/api/users/list.json | /mock/api_users_list.json | 用户列表 |
| /api/users/detail | /mock/api/users/detail.json | /mock/api_users_detail.json | 用户详情 |
| /service/config | /mock/service/config.json | /mock/service_config.json | 服务配置 |
| /v1/auth/login | /mock/v1/auth/login.json | /mock/v1_auth_login.json | 用户登录 |
智能回退机制
SwMock采用智能回退策略,确保最大兼容性:
- 优先尝试嵌套结构:先查找
/mock/api/users/list.json - 回退到扁平结构:如果嵌套文件不存在,查找
/mock/api_users_list.json - 转发到真实服务:如果两种格式都不存在,请求转发到真实服务器
Mock数据文件格式
基本格式
{
"code": "00000",
"msg": "操作成功",
"data": {
// 实际数据内容
},
"_mock": {
// Mock配置(可选)
"delay": 500,
"errorRate": 0.05,
"errorStatus": [500, 502],
"description": "接口描述"
}
}完整示例
用户列表 (/mock/api/users/list.json):
{
"code": "00000",
"msg": "获取用户列表成功",
"data": {
"total": 100,
"page": 1,
"pageSize": 10,
"list": [
{
"id": 1,
"name": "张三",
"email": "[email protected]",
"status": "active",
"createTime": "2024-01-15 10:30:00"
},
{
"id": 2,
"name": "李四",
"email": "[email protected]",
"status": "inactive",
"createTime": "2024-01-16 14:20:00"
}
]
},
"_mock": {
"delay": [200, 800], // 随机延迟200-800ms
"errorRate": 0.05, // 5%概率返回错误
"errorStatus": [500, 502], // 错误状态码
"description": "用户列表接口"
}
}用户详情 (/mock/api/users/detail.json):
{
"code": "00000",
"msg": "获取用户详情成功",
"data": {
"id": 1,
"name": "张三",
"email": "[email protected]",
"phone": "13800138000",
"avatar": "https://example.com/avatar/zhangsan.jpg",
"profile": {
"age": 28,
"gender": "male",
"department": "技术部",
"position": "前端工程师"
},
"permissions": ["user:read", "user:write"],
"lastLoginTime": "2024-01-20 15:30:00"
},
"_mock": {
"delay": 300,
"errorRate": 0.02,
"description": "用户详情接口"
}
}文件命名规范
推荐命名规则
- 使用小写字母:
list.json,不是List.json - 使用连字符分隔:
user-profile.json,不是userProfile.json - 语义化命名:
create.json、update.json、delete.json - RESTful风格:
list.json- 列表查询detail.json- 详情查询create.json- 创建操作update.json- 更新操作delete.json- 删除操作
HTTP方法映射
| HTTP方法 | 推荐文件名 | 说明 |
|----------|-----------|------|
| GET | list.json | 获取列表 |
| GET | detail.json | 获取详情 |
| POST | create.json | 创建资源 |
| PUT | update.json | 更新资源 |
| DELETE | delete.json | 删除资源 |
| PATCH | patch.json | 部分更新 |
🎯 多响应配置功能
功能概述
SwMock 支持多响应配置功能,允许同一个 API 接口根据不同的请求参数(query 参数、请求体内容、请求头等)返回相应的模拟数据。这个功能特别适用于需要根据不同条件返回不同数据的复杂业务场景。
核心特性
1. 智能参数匹配
- 多种匹配类型:支持 query 参数、请求体、请求头、HTTP 方法、URL 路径匹配
- 丰富匹配规则:精确匹配、模糊匹配、正则表达式、数值范围、存在性检查等
- 灵活配置:支持大小写忽略、正则表达式标志等高级选项
2. 权重优先级系统
- 权重排序:高权重响应优先匹配
- 智能回退:未匹配时自动使用默认响应
- 条件组合:支持多条件组合匹配
3. 完全向后兼容
- 无缝迁移:现有单响应配置无需修改
- 自动识别:系统自动识别配置类型
- 渐进升级:可逐步迁移到多响应配置
配置文件结构
多响应配置示例
{
"default": {
"status": 200,
"data": {
"code": "00000",
"msg": "默认响应",
"data": []
},
"delay": 300
},
"responses": [
{
"name": "管理员用户列表",
"weight": 100,
"conditions": [
{
"type": "query",
"target": "role",
"value": "admin",
"rule": { "mode": "exact" }
}
],
"response": {
"status": 200,
"data": {
"code": "00000",
"msg": "管理员用户列表",
"data": {
"list": [
{
"id": 1,
"name": "管理员",
"role": "admin"
}
]
}
},
"headers": {
"X-User-Role": "admin"
}
}
}
],
"global": {
"delay": [100, 300],
"errorRate": 0.02,
"headers": {
"X-API-Version": "v1.0"
}
}
}匹配条件类型
1. Query 参数匹配
{
"type": "query",
"target": "role",
"value": "admin",
"rule": { "mode": "exact" }
}2. 请求体匹配
{
"type": "body",
"target": "user.type",
"value": "premium",
"rule": { "mode": "exact" }
}3. 请求头匹配
{
"type": "header",
"target": "x-user-level",
"value": "vip",
"rule": { "mode": "exact", "ignoreCase": true }
}4. HTTP 方法匹配
{
"type": "method",
"target": "method",
"value": "POST",
"rule": { "mode": "exact" }
}匹配规则
1. 精确匹配 (exact)
{
"mode": "exact",
"ignoreCase": false
}2. 包含匹配 (contains)
{
"mode": "contains",
"ignoreCase": true
}3. 正则表达式匹配 (regex)
{
"mode": "regex",
"regexFlags": "gi"
}4. 数值范围匹配 (range)
{
"mode": "range"
}5. 存在性检查 (exists)
{
"mode": "exists"
}使用示例
用户列表多响应配置
创建 /mock/api/users/multi-response-list.json:
{
"default": {
"status": 200,
"data": {
"code": "00000",
"msg": "用户列表获取成功(默认响应)",
"data": {
"total": 10,
"page": 1,
"pageSize": 10,
"list": [
{
"id": 1,
"name": "张三",
"email": "[email protected]",
"status": "active"
}
]
}
}
},
"responses": [
{
"name": "管理员用户列表",
"weight": 100,
"conditions": [
{
"type": "query",
"target": "role",
"value": "admin",
"rule": { "mode": "exact" }
}
],
"response": {
"status": 200,
"data": {
"code": "00000",
"msg": "管理员用户列表获取成功",
"data": {
"list": [
{
"id": 1,
"name": "超级管理员",
"email": "[email protected]",
"role": "admin",
"permissions": ["all"]
}
]
}
},
"headers": {
"X-User-Role": "admin"
}
}
},
{
"name": "分页查询",
"weight": 80,
"conditions": [
{
"type": "query",
"target": "page",
"value": [2, 10],
"rule": { "mode": "range" }
}
],
"response": {
"status": 200,
"data": {
"code": "00000",
"msg": "分页用户列表获取成功",
"data": {
"total": 100,
"page": 2,
"pageSize": 10,
"list": [
{
"id": 11,
"name": "用户11",
"email": "[email protected]"
}
]
}
}
}
}
]
}测试多响应功能
// 初始化 SwMock
const swMock = createSwMock();
await swMock.init({
enabled: true,
debug: true
});
await swMock.enable();
// 测试不同的请求参数
// 1. 默认响应
const response1 = await fetch('/api/users/multi-response-list');
console.log('默认响应:', await response1.json());
// 2. 管理员响应
const response2 = await fetch('/api/users/multi-response-list?role=admin');
console.log('管理员响应:', await response2.json());
// 3. 分页响应
const response3 = await fetch('/api/users/multi-response-list?page=2');
console.log('分页响应:', await response3.json());💡 使用示例
基础使用示例
Vue.js 项目集成
// main.js
import { createApp } from 'vue';
import { createSwMock } from 'buse-sw-mock';
import App from './App.vue';
const app = createApp(App);
// 开发环境启用SwMock
if (process.env.NODE_ENV === 'development') {
const swMock = createSwMock();
swMock.init({
enabled: true,
debug: true,
mockDataPath: '/mock',
scope: '/',
interceptPatterns: ['/api/']
}).then(() => {
return swMock.enable();
}).then(() => {
console.log('SwMock已启用');
app.mount('#app');
}).catch(error => {
console.error('SwMock初始化失败:', error);
app.mount('#app');
});
} else {
app.mount('#app');
}React 项目集成
// index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import { createSwMock } from 'buse-sw-mock';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
async function initApp() {
// 开发环境启用SwMock
if (process.env.NODE_ENV === 'development') {
try {
const swMock = createSwMock();
await swMock.init({
enabled: true,
debug: true,
mockDataPath: '/mock',
interceptPatterns: ['/api/', '/service/']
});
await swMock.enable();
console.log('SwMock已启用');
} catch (error) {
console.error('SwMock初始化失败:', error);
}
}
root.render(<App />);
}
initApp();Angular 项目集成
// main.ts
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { createSwMock } from 'buse-sw-mock';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
async function bootstrap() {
// 开发环境启用SwMock
if (!environment.production) {
try {
const swMock = createSwMock();
await swMock.init({
enabled: true,
debug: true,
mockDataPath: '/assets/mock',
scope: '/',
interceptPatterns: ['/api/']
});
await swMock.enable();
console.log('SwMock已启用');
} catch (error) {
console.error('SwMock初始化失败:', error);
}
}
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
}
bootstrap();高级使用示例
微前端架构集成
// 主应用 (main-app)
const mainSwMock = createSwMock();
await mainSwMock.init({
enabled: true,
scope: '/main-app/',
mockDataPath: '/main-app/mock',
workerUrl: '/main-app/sw-mock-worker.js',
interceptPatterns: ['/main-app/api/']
});
// 子应用 (sub-app)
const subSwMock = createSwMock();
await subSwMock.init({
enabled: true,
scope: '/sub-app/',
mockDataPath: '/sub-app/mock',
workerUrl: '/sub-app/sw-mock-worker.js',
interceptPatterns: ['/sub-app/api/']
});条件性启用
const swMock = createSwMock();
// 根据环境变量决定是否启用
const shouldEnableMock =
process.env.NODE_ENV === 'development' ||
process.env.REACT_APP_ENABLE_MOCK === 'true' ||
localStorage.getItem('enableMock') === 'true';
await swMock.init({
enabled: shouldEnableMock,
debug: shouldEnableMock,
mockDataPath: '/mock'
});
if (shouldEnableMock) {
await swMock.enable();
console.log('Mock模式已启用');
}动态配置切换
const swMock = createSwMock();
await swMock.init({
enabled: false,
debug: true
});
// 运行时切换配置
document.getElementById('enableMock').addEventListener('click', async () => {
await swMock.enable();
console.log('Mock已启用');
});
document.getElementById('disableMock').addEventListener('click', async () => {
await swMock.disable();
console.log('Mock已禁用');
});
// 切换mock数据路径
document.getElementById('switchPath').addEventListener('click', async () => {
await swMock.updateConfig({
mockDataPath: '/alternative-mock'
});
console.log('Mock路径已切换');
});网络故障模拟示例
const swMock = createSwMock();
await swMock.init({
enabled: true,
debug: true
});
// 启用网络故障模拟
await swMock.enableNetworkFailure({
scenarios: {
// 模拟服务器错误
httpErrors: {
enabled: true,
statusCodes: [500, 502, 503],
rate: 0.1 // 10%的请求返回错误
},
// 模拟网络延迟
responseDelay: {
enabled: true,
minDelay: 2000,
maxDelay: 5000,
rate: 0.3 // 30%的请求有延迟
},
// 模拟连接超时
timeout: {
enabled: true,
duration: 10000,
rate: 0.05 // 5%的请求超时
}
}
});
console.log('网络故障模拟已启用');事件监听示例
const swMock = createSwMock();
// 监听状态变化
swMock.on('enabled', () => {
console.log('SwMock已启用');
updateUI('enabled');
});
swMock.on('disabled', () => {
console.log('SwMock已禁用');
updateUI('disabled');
});
swMock.on('error', (error) => {
console.error('SwMock错误:', error);
showErrorMessage(error.message);
});
swMock.on('configUpdated', (config) => {
console.log('配置已更新:', config);
updateConfigDisplay(config);
});
function updateUI(status) {
const statusElement = document.getElementById('status');
statusElement.textContent = status === 'enabled' ? '已启用' : '已禁用';
statusElement.className = status;
}
function showErrorMessage(message) {
const errorElement = document.getElementById('error');
errorElement.textContent = message;
errorElement.style.display = 'block';
}
function updateConfigDisplay(config) {
document.getElementById('mockPath').textContent = config.mockDataPath;
document.getElementById('scope').textContent = config.scope;
}🏆 最佳实践
项目组织最佳实践
1. 目录结构组织
project/
├── public/
│ ├── sw-mock-worker.js
│ └── mock/
│ ├── api/ # API相关mock
│ │ ├── auth/ # 认证相关
│ │ ├── users/ # 用户管理
│ │ ├── orders/ # 订单管理
│ │ └── products/ # 产品管理
│ ├── service/ # 服务配置
│ └── common/ # 通用数据
├── src/
│ ├── utils/
│ │ └── mock-setup.js # Mock配置文件
│ └── main.js
└── mock-config.json # Mock配置文件(可选)2. 配置文件管理
创建专门的Mock配置文件:
// src/utils/mock-setup.js
import { createSwMock } from 'buse-sw-mock';
const isDevelopment = process.env.NODE_ENV === 'development';
const enableMock = isDevelopment || localStorage.getItem('enableMock') === 'true';
export async function setupMock() {
if (!enableMock) return null;
const swMock = createSwMock();
try {
await swMock.init({
enabled: true,
debug: isDevelopment,
mockDataPath: '/mock',
scope: '/',
interceptPatterns: ['/api/', '/service/'],
excludePatterns: [
'.js', '.css', '.png', '.jpg', '.gif', '.svg',
'.woff', '.woff2', '.ttf', '.eot',
'/sw-mock-worker.js'
],
defaultDelay: 300,
errorRate: 0.02
});
await swMock.enable();
// 开发环境下添加全局访问
if (isDevelopment) {
window.swMock = swMock;
}
console.log('SwMock已启用');
return swMock;
} catch (error) {
console.error('SwMock初始化失败:', error);
return null;
}
}
// 导出便捷方法
export function enableMockInProduction() {
localStorage.setItem('enableMock', 'true');
location.reload();
}
export function disableMockInProduction() {
localStorage.removeItem('enableMock');
location.reload();
}3. Mock数据管理
标准化数据格式:
// 创建Mock数据模板
const createMockResponse = (data, options = {}) => ({
code: options.code || '00000',
msg: options.msg || '操作成功',
data: data,
timestamp: Date.now(),
_mock: {
delay: options.delay || [200, 500],
errorRate: options.errorRate || 0.02,
errorStatus: options.errorStatus || [500, 502],
description: options.description || ''
}
});
// 使用示例
const userListMock = createMockResponse(
{
total: 100,
list: [/* 用户数据 */]
},
{
description: '用户列表接口',
delay: 300
}
);开发流程最佳实践
1. 渐进式启用
// 阶段1:仅在开发环境启用
if (process.env.NODE_ENV === 'development') {
await setupMock();
}
// 阶段2:支持测试环境
if (['development', 'test'].includes(process.env.NODE_ENV)) {
await setupMock();
}
// 阶段3:支持生产环境调试
const enableMock =
process.env.NODE_ENV === 'development' ||
process.env.ENABLE_MOCK === 'true' ||
localStorage.getItem('enableMock') === 'true';
if (enableMock) {
await setupMock();
}2. 环境变量配置
# .env.development
REACT_APP_ENABLE_MOCK=true
REACT_APP_MOCK_PATH=/mock
REACT_APP_MOCK_SCOPE=/
# .env.production
REACT_APP_ENABLE_MOCK=false
# .env.test
REACT_APP_ENABLE_MOCK=true
REACT_APP_MOCK_PATH=/test-mock3. 团队协作规范
Mock数据命名规范:
- 使用语义化的文件名
- 保持与API文档一致的路径结构
- 添加详细的注释和描述
版本控制:
# 不提交个人Mock配置
/public/mock/personal/
.mock-config.local.json
# 提交团队共享的Mock数据
/public/mock/api/
/public/mock/service/性能优化最佳实践
1. 合理设置拦截范围
// ❌ 不推荐:拦截所有请求
interceptPatterns: ['*']
// ✅ 推荐:精确拦截
interceptPatterns: ['/api/', '/service/']
// ✅ 推荐:使用scope限制范围
scope: '/api/',
interceptPatterns: ['/']2. 优化Mock数据大小
// ❌ 不推荐:返回大量数据
{
"data": {
"list": [/* 1000条记录 */]
}
}
// ✅ 推荐:分页返回
{
"data": {
"list": [/* 10-20条记录 */],
"total": 1000,
"page": 1,
"pageSize": 20
}
}3. 合理设置延迟
// 模拟真实网络延迟
{
"_mock": {
"delay": [100, 300], // 快速接口
// "delay": [500, 1000], // 慢速接口
// "delay": [1000, 3000], // 复杂查询接口
}
}多响应配置最佳实践
1. 配置文件组织
// 推荐的多响应配置结构
{
"default": {
// 默认响应,必须提供
"status": 200,
"data": { /* 默认数据 */ },
"delay": 300
},
"responses": [
{
"name": "描述性名称", // 便于维护
"weight": 100, // 明确权重
"conditions": [
{
"type": "query",
"target": "role",
"value": "admin",
"rule": { "mode": "exact" },
"required": true // 明确是否必需
}
],
"response": {
"status": 200,
"data": { /* 响应数据 */ },
"headers": { /* 自定义响应头 */ }
}
}
],
"global": {
// 全局配置
"delay": [100, 300],
"errorRate": 0.02,
"headers": {
"X-API-Version": "v1.0"
}
}
}2. 权重设计原则
// 权重分配建议
{
"responses": [
{
"name": "特殊用户(最高优先级)",
"weight": 100,
"conditions": [/* 最具体的条件 */]
},
{
"name": "普通用户(中等优先级)",
"weight": 80,
"conditions": [/* 一般条件 */]
},
{
"name": "兜底响应(最低优先级)",
"weight": 10,
"conditions": [/* 宽泛条件 */]
}
]
}3. 条件设计最佳实践
// ✅ 推荐:明确的条件配置
{
"conditions": [
{
"type": "query",
"target": "role",
"value": "admin",
"rule": { "mode": "exact" },
"required": true
},
{
"type": "header",
"target": "x-user-level",
"value": "vip",
"rule": { "mode": "exact", "ignoreCase": true },
"required": false
}
]
}
// ❌ 避免:过于复杂的条件
{
"conditions": [
{
"type": "body",
"target": "user.profile.settings.preferences.theme",
"value": "dark",
"rule": { "mode": "exact" }
}
]
}4. 测试和验证
// 创建测试用例验证多响应配置
const testCases = [
{
name: '默认响应测试',
url: '/api/users/list',
expected: { msg: '默认响应' }
},
{
name: '管理员响应测试',
url: '/api/users/list?role=admin',
expected: { msg: '管理员用户列表' }
},
{
name: '分页响应测试',
url: '/api/users/list?page=2',
expected: { data: { page: 2 } }
}
];
// 自动化测试
for (const testCase of testCases) {
const response = await fetch(testCase.url);
const data = await response.json();
console.assert(
data.msg.includes(testCase.expected.msg),
`${testCase.name} 失败`
);
}调试和监控最佳实践
1. 开启调试模式
await swMock.init({
debug: true, // 开启详细日志
// 其他配置...
});
// 监听所有事件
swMock.on('*', (eventName, ...args) => {
console.log(`[SwMock Event] ${eventName}:`, args);
});2. 多响应调试
// 启用多响应调试日志
await swMock.init({
debug: true,
enabled: true
});
// 监听多响应匹配事件
swMock.on('multiResponseMatched', (data) => {
console.log('多响应匹配:', {
url: data.url,
matchedResponse: data.response.name,
weight: data.response.weight,
conditions: data.conditions
});
});3. 状态监控
// 定期检查状态
setInterval(async () => {
const status = await swMock.getStatus();
console.log('SwMock状态:', {
enabled: status.enabled,
intercepted: status.endpointsCount,
scope: status.scope,
path: status.mockDataPath,
multiResponseEnabled: status.multiResponseEnabled
});
}, 30000);4. 错误处理
swMock.on('error', (error) => {
// 发送错误报告
console.error('SwMock错误:', error);
// 可选:发送到错误监控服务
if (window.Sentry) {
window.Sentry.captureException(error);
}
});
// 多响应特定错误处理
swMock.on('multiResponseError', (error) => {
console.error('多响应配置错误:', {
url: error.url,
configFile: error.configFile,
error: error.message
});
});❓ 常见问题
安装和配置问题
Q1: ServiceWorker文件404错误
问题:控制台显示 Failed to load resource: the server responded with a status of 404 (Not Found) sw-mock-worker.js
解决方案:
- 确保将
sw-mock-worker.js文件复制到public目录 - 检查
workerUrl配置是否正确 - 确保服务器能够正确提供静态文件
// 正确的配置
await swMock.init({
workerUrl: '/sw-mock-worker.js' // 确保文件存在于 public/sw-mock-worker.js
});Q2: Mock数据不生效
问题:请求没有被拦截,返回的是真实服务器数据
解决方案:
- 检查
interceptPatterns配置是否包含请求路径 - 确认
scope配置是否覆盖请求路径 - 检查Mock数据文件是否存在且格式正确
// 检查配置
const status = await swMock.getStatus();
console.log('拦截模式:', status.interceptPatterns);
console.log('作用域:', status.scope);
console.log('Mock路径:', status.mockDataPath);
// 检查请求是否匹配
const requestUrl = '/api/users/list';
const isMatched = status.interceptPatterns.some(pattern =>
requestUrl.includes(pattern)
);
console.log('请求是否匹配:', isMatched);Q3: HTTPS环境下ServiceWorker无法注册
问题:在HTTPS环境下ServiceWorker注册失败
解决方案:
- 确保ServiceWorker文件通过HTTPS提供
- 检查Content-Type是否正确设置为
application/javascript - 确保没有CORS问题
// 检查ServiceWorker支持
if ('serviceWorker' in navigator) {
console.log('ServiceWorker支持正常');
} else {
console.error('当前环境不支持ServiceWorker');
}多响应配置问题
Q4: 多响应配置不生效
问题:创建了多响应配置文件,但请求仍然返回默认响应
解决方案:
- 检查配置文件格式是否正确
- 确认条件匹配逻辑是否正确
- 验证权重设置是否合理
// 检查多响应配置
const response = await fetch('/api/users/list?role=admin');
const headers = response.headers;
// 查看响应头中的调试信息
console.log('匹配的响应:', headers.get('X-Mock-Response-Name'));
console.log('匹配权重:', headers.get('X-Mock-Response-Weight'));
console.log('匹配条件:', headers.get('X-Mock-Matched-Conditions'));Q5: 条件匹配不准确
问题:请求参数明明符合条件,但没有匹配到预期的响应
解决方案:
- 检查匹配规则配置
- 确认参数类型和格式
- 启用调试模式查看匹配过程
// 启用详细调试
await swMock.init({
debug: true,
enabled: true
});
// 查看匹配过程日志
// 控制台会显示详细的匹配信息Q6: 权重优先级不正确
问题:低权重的响应被优先匹配
解决方案:
- 检查权重数值设置(数值越大优先级越高)
- 确认条件的具体程度
- 避免权重相同的情况
// 正确的权重设置
{
"responses": [
{
"name": "最具体条件",
"weight": 100, // 最高优先级
"conditions": [/* 最具体的条件 */]
},
{
"name": "一般条件",
"weight": 50, // 中等优先级
"conditions": [/* 一般条件 */]
}
]
}功能使用问题
Q7: 嵌套目录结构不生效
问题:创建了嵌套目录结构,但请求仍然返回404
解决方案:
- 确保文件路径与URL路径完全匹配
- 检查文件扩展名是否为
.json - 验证JSON格式是否正确
# 正确的文件路径示例
# URL: /api/users/list
# 文件: public/mock/api/users/list.json
# 检查文件是否存在
ls -la public/mock/api/users/list.jsonQ5: 自定义mockDataPath不生效
问题:设置了自定义的 mockDataPath,但仍然从默认路径加载
解决方案:
- 确保在
init()时设置了mockDataPath - 检查路径格式是否正确(以
/开头) - 确保新路径下的文件存在
// 正确设置自定义路径
await swMock.init({
mockDataPath: '/custom-mock', // 确保以/开头
enabled: true
});
// 验证配置
const status = await swMock.getStatus();
console.log('当前Mock路径:', status.mockDataPath);Q6: Scope配置导致请求不被拦截
问题:设置了 scope 后,某些请求不再被拦截
解决方案:
- 确保请求URL在scope范围内
- 检查ServiceWorker文件位置是否支持该scope
- 理解scope的工作原理
// 示例:scope配置说明
await swMock.init({
scope: '/api/', // 只拦截 /api/ 开头的请求
workerUrl: '/sw-mock-worker.js' // 文件在根目录,支持任意scope
});
// 这些请求会被拦截:
// ✅ /api/users/list
// ✅ /api/orders/create
// 这些请求不会被拦截:
// ❌ /service/config
// ❌ /v1/auth/login性能和兼容性问题
Q7: 页面加载变慢
问题:启用SwMock后页面加载明显变慢
解决方案:
- 优化
excludePatterns配置,排除不需要拦截的资源 - 减少Mock数据文件大小
- 合理设置延迟时间
await swMock.init({
excludePatterns: [
'.js', '.css', // 排除静态资源
'.png', '.jpg', '.gif', // 排除图片
'.woff', '.ttf', // 排除字体
'/health-check', // 排除健康检查
'/metrics' // 排除监控接口
]
});Q8: 浏览器兼容性问题
问题:在某些浏览器中SwMock无法正常工作
解决方案:
- 检查浏览器是否支持ServiceWorker
- 确保使用HTTPS或localhost
- 添加兼容性检查
// 兼容性检查
function checkCompatibility() {
if (!('serviceWorker' in navigator)) {
console.warn('当前浏览器不支持ServiceWorker');
return false;
}
if (location.protocol !== 'https:' && location.hostname !== 'localhost') {
console.warn('ServiceWorker需要HTTPS环境或localhost');
return false;
}
return true;
}
// 条件性初始化
if (checkCompatibility()) {
await swMock.init({ enabled: true });
} else {
console.log('跳过SwMock初始化,使用真实API');
}调试和故障排除
Q9: 如何调试Mock数据加载
解决方案:
- 开启调试模式
- 检查浏览器开发者工具
- 使用状态监控
// 开启详细调试
await swMock.init({
debug: true,
enabled: true
});
// 监听所有事件
swMock.on('*', (eventName, data) => {
console.log(`[SwMock] ${eventName}:`, data);
});
// 检查网络面板
// 1. 打开开发者工具 -> Network
// 2. 查看请求是否有 "from ServiceWorker" 标识
// 3. 检查响应头是否包含 X-Mock-Response: trueQ10: 生产环境意外启用Mock
问题:生产环境中意外启用了Mock功能
解决方案:
- 添加环境检查
- 使用构建时配置
- 添加安全开关
// 安全的初始化方式
const isDevelopment = process.env.NODE_ENV === 'development';
const isExplicitlyEnabled = process.env.ENABLE_MOCK === 'true';
const isLocalStorageEnabled = localStorage.getItem('enableMock') === 'true';
// 只在明确允许的情况下启用
const shouldEnableMock = isDevelopment || (isExplicitlyEnabled && isLocalStorageEnabled);
if (shouldEnableMock) {
console.warn('Mock模式已启用,请确保这是预期行为');
await swMock.init({ enabled: true });
} else {
console.log('使用真实API');
}🧪 测试服务
SwMock 提供了便捷的测试服务功能,让您可以通过简单的命令启动本地测试服务器,快速验证SwMock的功能和配置。
快速启动测试服务
安装SwMock后,可以立即启动测试服务:
# 基础启动
npx swmock-test
# 自动打开浏览器
npx swmock-test --open
# 指定端口
npx swmock-test --port=8080
# 组合使用
npx swmock-test --open --port=8080测试服务功能
🎯 核心功能
- SwMock初始化控制:可配置ServiceWorker URL、Mock数据路径、拦截模式
- 手动URL测试:支持不同HTTP方法的API拦截测试
- includeInterceptPrefix配置测试:专门测试新增的前缀配置功能
- 对比测试:自动对比不同配置下的路径映射行为
🔧 技术特性
- 零配置启动:一个命令即可启动测试服务
- 自动文件服务:自动提供所需的静态文件
- 跨平台支持:支持Windows、macOS、Linux
- 智能MIME类型处理:正确处理ServiceWorker和JSON文件
使用示例
项目集成示例
# 在您的项目中
cd my-project
npm install @buse/sw-mock
# 确保项目结构
your-project/
├── sw-mock-worker.js # ServiceWorker文件
├── mock/ # 模拟数据目录
│ ├── api/users/list.json # 示例数据
│ └── users/list.json # 示例数据
└── package.json
# 启动测试服务
npx swmock-test --open
# 访问: http://localhost:3000/swmock-test-page.htmlpackage.json 集成
{
"scripts": {
"test:swmock": "swmock-test",
"test:swmock-open": "swmock-test --open --port=3001"
}
}命令选项
| 选项 | 描述 | 默认值 |
|------|------|--------|
| --open, -o | 启动后自动打开浏览器 | false |
| --port=<端口> | 指定服务器端口 | 3000 |
| --host=<主机> | 指定服务器主机 | localhost |
| --help, -h | 显示帮助信息 | - |
测试页面功能
访问测试页面后,您可以:
- 初始化SwMock:配置并启动SwMock服务
- 手动URL测试:测试特定API的拦截效果
- 前缀配置对比:验证
includeInterceptPrefix功能 - 查看详细结果:包括响应状态、文件路径、映射类型等
故障排除
常见问题
端口被占用:
npx swmock-test --port=8080 # 使用其他端口ServiceWorker文件未找到:
# 确保文件存在
ls sw-mock-worker.js
# 或从dist目录复制
cp node_modules/@buse/sw-mock/dist/sw-mock-worker.js ./模拟数据文件未找到:
# 创建示例数据
mkdir -p mock/api/users
echo '{"code":200,"msg":"测试数据","data":[]}' > mock/api/users/list.json💡 提示: 测试服务是开发工具,仅用于开发和测试环境,不要在生产环境中使用。
🚀 高级功能
高级测试框架
SwMock 提供了一个完整的测试框架,用于验证多响应配置功能:
1. 测试框架特性
- 自动化测试:基于配置文件自动生成测试用例
- 实时监控:实时显示测试进度、日志和结果
- 模块化设计:清晰的架构分层和职责分离
- 性能测试:内置性能测试工具,支持并发测试
2. 使用测试框架
访问高级测试框架页面:
http://localhost:8080/examples/advanced-test-framework.html或者通过代码方式使用:
// 引入测试框架组件
// <script src="examples/test-framework/core/SwMockTestFramework.js"></script>
// <script src="examples/test-framework/utils/TestUtils.js"></script>
// <script src="examples/test-framework/config/testConfig.js"></script>
// <script src="examples/test-framework/suites/MultiResponseTestSuite.js"></script>
// 初始化测试框架
const testFramework = new SwMockTestFramework({
debug: true,
timeout: 30000
});
await testFramework.init();
// 注册测试套件
const testSuite = new MultiResponseTestSuite();
const suites = testSuite.getAllSuites();
suites.forEach(suite => {
testFramework.registerTestSuite(suite.name, suite);
});
// 运行所有测试
const report = await testFramework.runAllTests();
console.log('测试报告:', report);3. 测试套件覆盖
| 测试套件 | 测试用例数 | 覆盖场景 | |---------|-----------|---------| | 用户管理 | 6个 | 默认响应、管理员列表、分页、搜索、状态筛选、POST创建 | | 订单管理 | 5个 | 默认列表、用户查询、状态筛选、VIP订单、日期范围 | | 性能测试 | 2个 | 响应时间测试、并发请求测试 | | 边界条件 | 3个 | 无效参数、空值、特殊字符 |
4. 自定义测试用例
// 在 testConfig.js 中添加自定义测试场景
const customScenario = {
name: '自定义测试场景',
description: '测试特定业务逻辑',
tests: [
{
name: '自定义测试用例',
description: '测试描述',
endpoint: 'users.list',
method: 'GET',
params: { customParam: 'value' },
expectedStatus: 200,
assertions: [
{ type: 'statusCode', value: 200 },
{ type: 'contains', path: 'msg', value: '期望内容' }
]
}
]
};
// 添加到配置中
TEST_CONFIG.scenarios.customScenario = customScenario;5. 命令行测试
# 运行自动化测试脚本
cd examples/test-framework/scripts
node runTests.js
# 生成测试报告
# 报告将保存在 test-results/ 目录下
# - test-results.json (JSON格式)
# - test-report.html (HTML格式)
# - junit-results.xml (JUnit格式)实现总结
技术实现亮点
- 类型系统扩展:在
src/types/index.ts中新增了完整的类型定义 - 请求上下文提取:实现了
extractRequestContext函数,能够从请求中提取各种参数 - 参数匹配引擎:实现了强大的匹配引擎,支持多种匹配规则
- 响应选择算法:实现了智能响应选择逻辑
功能完整性
✅ 支持多种参数匹配规则 ✅ 智能权重优先级系统 ✅ 完全向后兼容 ✅ 丰富的配置选项 ✅ 详细的调试信息
性能优化
✅ 高效的匹配算法 ✅ 智能缓存机制 ✅ 按需加载模拟数据 ✅ 优化的请求处理流程
开发体验
✅ 完整的 TypeScript 类型支持 ✅ 详细的文档和示例 ✅ 直观的测试页面 ✅ 清晰的错误提示
插件系统
SwMock 支持插件扩展,您可以开发自定义插件来扩展功能:
// 创建自定义插件
class CustomPlugin {
constructor(options) {
this.options = options;
}
install(swMock) {
// 插件安装逻辑
swMock.on('request', this.handleRequest.bind(this));
}
handleRequest(request) {
// 自定义请求处理逻辑
console.log('Custom plugin handling:', request.url);
}
}
// 使用插件
const swMock = createSwMock();
swMock.use(new CustomPlugin({ /* 配置选项 */ }));🔄 迁移指南
从旧版本升级
从 v1.0.0 升级到 v1.0.2+
主要变更:
- 新增
mockDataPath配置选项 - 新增
scope配置选项 - 支持嵌套目录结构
- 改进的错误处理和日志
升级步骤:
- 更新依赖:
npm update buse-sw-mock- 更新配置(可选):
// 旧版本配置
await swMock.init({
enabled: true,
workerUrl: '/sw-mock-worker.js'
});
// 新版本配置(向后兼容)
await swMock.init({
enabled: true,
workerUrl: '/sw-mock-worker.js',
mockDataPath: '/mock', // 新增:自定义Mock路径
scope: '/' // 新增:ServiceWorker作用域
});- 迁移Mock数据(可选):
# 可选:将扁平结构迁移到嵌套结构
mkdir -p public/mock/api/users
mv public/mock/api_users_list.json public/mock/api/users/list.json
mv public/mock/api_users_detail.json public/mock/api/users/detail.json兼容性说明:
- ✅ 完全向后兼容,现有代码无需修改
- ✅ 扁平结构的Mock文件继续有效
- ✅ 所有现有API保持不变
从其他Mock方案迁移
从 Mock.js 迁移
Mock.js 配置:
// Mock.js 方式
import Mock from 'mockjs';
Mock.mock('/api/users/list', 'get', {
code: '00000',
data: {
'list|10': [{
'id|+1': 1,
'name': '@cname',
'email': '@email'
}]
}
});SwMock 方式:
// SwMock 方式
// 1. 创建 public/mock/api/users/list.json
{
"code": "00000",
"data": {
"list": [
{"id": 1, "name": "张三", "email": "[email protected]"},
{"id": 2, "name": "李四", "email": "[email protected]"}
]
}
}
// 2. 初始化 SwMock
await swMock.init({
enabled: true,
interceptPatterns: ['/api/']
});从 MSW 迁移
MSW 配置:
// MSW 方式
import { rest } from 'msw';
import { setupWorker } from 'msw';
const worker = setupWorker(
rest.get('/api/users/list', (req, res, ctx) => {
return res(
ctx.json({
code: '00000',
data: { list: [] }
})
);
})
);
worker.start();SwMock 方式:
// SwMock 方式更简单
await swMock.init({
enabled: true,
mockDataPath: '/mock'
});
// Mock数据通过JSON文件管理,无需编写代码配置迁移工具
创建自动化迁移脚本:
// migrate-to-nested.js
const fs = require('fs');
const path = require('path');
function migrateToNestedStructure(mockDir = 'public/mock') {
const files = fs.readdirSync(mockDir);
files.forEach(file => {
if (file.endsWith('.json') && file.includes('_')) {
const oldPath = path.join(mockDir, file);
const newPath = file.replace(/_/g, '/');
const newDir = path.dirname(path.join(mockDir, newPath));
// 创建目录
fs.mkdirSync(newDir, { recursive: true });
// 移动文件
fs.renameSync(oldPath, path.join(mockDir, newPath));
console.log(`迁移: ${file} -> ${newPath}`);
}
});
}
// 运行迁移
migrateToNestedStructure();🔧 故障排除
常见错误及解决方案
错误1: "ServiceWorker registration failed"
错误信息:
DOMException: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/html').原因:ServiceWorker文件返回了HTML内容而不是JavaScript
解决方案:
- 确保
sw-mock-worker.js文件存在且内容正确 - 检查服务器配置,确保
.js文件返回正确的MIME类型 - 检查是否有重定向到404页面
// 添加错误处理
try {
await swMock.init({
enabled: true,
workerUrl: '/sw-mock-worker.js'
});
} catch (error) {
console.error('SwMock初始化失败:', error);
// 降级到无Mock模式
}错误2: "NetworkError when attempting to fetch resource"
错误信息:
TypeError: NetworkError when attempting to fetch resource.原因:网络连接问题或CORS限制
解决方案:
- 检查网络连接
- 确保在HTTPS环境或localhost下运行
- 检查CORS配置
// 添加网络检查
if (!navigator.onLine) {
console.warn('网络连接不可用,跳过SwMock初始化');
return;
}
// 检查协议
if (location.protocol !== 'https:' && location.hostname !== 'localhost') {
console.warn('ServiceWorker需要HTTPS环境');
}错误3: "The operation is insecure"
错误信息:
DOMException: The operation is insecure.原因:在不安全的上下文中尝试使用ServiceWorker
解决方案:
- 使用HTTPS协议
- 或在localhost环境下开发
- 添加安全上下文检查
// 检查安全上下文
if (!window.isSecureContext) {
console.warn('当前不是安全上下文,无法使用ServiceWorker');
return;
}调试工具和技巧
1. 浏览器开发者工具
Application面板:
- 查看ServiceWorker注册状态
- 检查ServiceWorker生命周期
- 手动更新或注销ServiceWorker
Network面板:
- 查看请求是否被ServiceWorker拦截
- 检查响应头中的Mock标识
- 分析请求时间和大小
Console面板:
- 查看SwMock日志输出
- 检查错误信息
- 执行调试命令
2. SwMock调试命令
在浏览器控制台中使用:
// 获取SwMock实例(如果设置了全局访问)
const swMock = window.swMock;
// 查看当前状态
await swMock.getStatus();
// 切换调试模式
await swMock.updateConfig({ debug: true });
// 查看拦截统计
console.log('拦截的端点数量:', (await swMock.getStatus()).endpointsCount);
// 手动触发配置更新
await swMock.updateConfig({
mockDataPath: '/debug-mock',
debug: true
});3. 日志分析
开启详细日志:
await swMock.init({
debug: true,
enabled: true
});
// 监听所有事件
swMock.on('*', (eventName, ...args) => {
console.group(`[SwMock] ${eventName}`);
console.log('参数:', args);
console.log('时间:', new Date().toISOString());
console.groupEnd();
});性能监控
1. 请求性能监控
// 监控请求性能
const originalFetch = window.fetch;
window.fetch = async function(...args) {
const start = performance.now();
const response = await originalFetch.apply(this, args);
const end = performance.now();
const isMocked = response.headers.get('X-Mock-Response') === 'true';
console.log(`请求耗时: ${end - start}ms, Mock: ${isMocked}, URL: ${args[0]}`);
return response;
};2. ServiceWorker性能监控
// 监控ServiceWorker状态
navigator.serviceWorker.addEventListener('message', event => {
if (event.data.type === 'PERFORMANCE_LOG') {
console.log('ServiceWorker性能:', event.data.data);
}
});问题报告模板
当遇到问题时,请提供以下信息:
**环境信息**:
- 浏览器版本:Chrome 120.0.0.0
- 操作系统:macOS 14.0
- SwMock版本:1.0.2
- 项目框架:React 18.2.0
**配置信息**:
```javascript
// 您的SwMock配置
await swMock.init({
enabled: true,
debug: true,
// ... 其他配置
});错误信息:
// 完整的错误堆栈
Error: ...重现步骤:
- 初始化SwMock
- 发起API请求
- 观察到的问题
期望行为: 描述您期望的正确行为
实际行为: 描述实际发生的情况
---
## 📞 技术支持
### 获取帮助
- **GitHub Issues**: [https://github.com/zyj3924/buse-sw-mock/issues](https://github.com/zyj3924/buse-sw-mock/issues)
- **邮箱支持**: [email protected]
- **文档更新**: 本文档会持续更新,请关注最新版本
### 贡献指南
欢迎贡献代码、文档或问题反馈:
1. Fork 项目仓库
2. 创建功能分支
3. 提交更改
4. 发起 Pull Request
### 版本发布
- **当前版本**: v1.0.2+
- **发布频率**: 根据功能需求和bug修复情况
- **版本策略**: 遵循语义化版本控制
---
## 📄 许可证
本项目采用 MIT 许可证,详情请查看 [LICENSE](LICENSE) 文件。
---
**最后更新**: 2024-01-20
**文档版本**: v1.0.2+
**作者**: SwMock 开发团队
## 📝 更新日志
### v1.0.2+ (2024-01-20)
#### 🎯 新增功能
- **多响应配置功能**:同一接口根据不同参数返回不同响应
- **智能参数匹配**:支持query参数、请求体、请求头等多种匹配方式
- **权重优先级系统**:高权重响应优先匹配,智能回退机制
- **高级测试框架**:完整的测试框架,支持自动化测试和性能测试
#### 🔧 技术改进
- **类型系统扩展**:新增完整的TypeScript类型定义
- **请求上下文提取**:实现强大的请求参数提取功能
- **参数匹配引擎**:支持精确匹配、模糊匹配、正则表达式等多种规则
- **响应选择算法**:智能的响应选择和回退机制
#### 📚 文档完善
- **完整集成指南**:详细的多响应配置使用指南
- **最佳实践文档**:配置设计和使用的最佳实践
- **测试框架文档**:完整的测试框架使用说明
- **故障排除指南**:常见问题和解决方案
#### ✅ 兼容性
- **完全向后兼容**:现有单响应配置无需修改
- **渐进式升级**:可逐步迁移到多响应配置
- **智能识别**:系统自动识别配置类型