请求录制与回放
功能概述
请求录制与回放是 vite-plugin-mock-dev-server 提供的高级功能,允许开发者在开发过程中自动捕获真实后端API响应,并在后续开发中回放这些录制数据。该功能提供"一次录制,随时使用"的mock数据方案,有效解决后端服务不稳定或尚未就绪时的开发痛点。
核心价值
- 降低前后端依赖:后端服务未就绪时,前端可基于录制的真实数据进行开发
- 提升开发稳定性:后端服务不稳定或不可用时,使用录制数据保障开发连续性
- 便于团队协作:录制的真实数据可在团队内共享,统一开发环境
- 简化API对接:录制真实响应后,前端调试可不重复请求后端
使用场景
场景1:后端服务未就绪
项目开发初期,后端API接口可能尚未开发完成。此时:
- 先使用mock数据进行前端页面开发
- 后端接口就绪后开启录制,捕获真实响应
- 后续开发可直接使用录制的真实数据,无需等待后端服务
场景2:后端服务不稳定
当后端服务偶发不可用、响应缓慢或返回不一致数据时:
- 在服务稳定时录制关键API的响应数据
- 服务不稳定时自动切换至录制数据回放模式
- 保障前端开发的连续性和稳定性
场景3:团队协作与数据共享
团队成员需要统一的mock数据环境:
- 录制关键业务接口的真实响应数据
- 将录制文件提交至版本控制系统
- 其他成员可直接使用录制数据进行开发
场景4:离线开发与演示
需要在无网络环境工作或进行演示时:
- 提前录制所需API的响应数据
- 离线状态下使用录制数据进行开发和演示
- 保障演示环境的数据稳定性和一致性
工作流程
三阶段工作流
txt
阶段1:Mock开发阶段(后端未就绪)
┌─────────────────────────────────────────────────────────┐
│ 前端请求 → Mock数据匹配 → 返回Mock │
│ │
│ 插件优先匹配mock文件配置 │
│ 返回预定义的mock数据 │
│ 录制功能可保持开启但此时不会实际生成录制数据 │
└─────────────────────────────────────────────────────────┘
阶段2:录制阶段(后端就绪)
┌─────────────────────────────────────────────────────────┐
│ 1. 开启录制:record: true │
│ │
│ 2. 请求处理流程: │
│ 前端请求 → Mock匹配失败 → 查找录制 │
│ ↓ │
│ 无录制 → 代理转发 │
│ ↓ │
│ 后端返回真实响应 │
│ ↓ │
│ 自动录制响应 │
│ ↓ │
│ 返回前端 │
│ │
│ 3. 录制文件自动生成至目录 │
└─────────────────────────────────────────────────────────┘
阶段3:回放阶段(后端不稳定/离线)
┌─────────────────────────────────────────────────────────┐
│ 请求处理流程: │
│ 前端请求 → Mock匹配失败 → 查找录制 │
│ ↓ │
│ 有录制 → 使用录制数据 │
│ 无录制 → 降级至代理 │
│ │
│ 录制数据有效时优先使用,过期后自动清理 │
└─────────────────────────────────────────────────────────┘请求处理优先级
txt
请求到达
│
▼
┌─────────────────────────────────────┐
│ 1. Mock数据匹配 │
│ - 匹配成功 → 使用Mock数据 │
│ - 匹配失败 → 继续 │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 2. 录制数据查找(回放开启时) │
│ - 找到有效录制 → 使用录制 │
│ - 未找到/过期 → 继续 │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 3. 代理转发(录制开启时记录) │
│ - 转发至后端服务 │
│ - 自动记录响应 │
└─────────────────────────────────────┘配置说明
快速启用
一键开启录制与回放的最简方式:
ts
// vite.config.ts
import { defineConfig } from 'vite'
import { mockDevServerPlugin } from 'vite-plugin-mock-dev-server'
export default defineConfig({
plugins: [
mockDevServerPlugin({
record: true
})
]
})当record设为true时,插件将以默认配置启用录制:
- 录制功能开启
- 回放功能自动开启
- 录制数据存储于
mock/.recordings目录
完整配置
ts
// vite.config.ts
import { defineConfig } from 'vite'
import { mockDevServerPlugin } from 'vite-plugin-mock-dev-server'
export default defineConfig({
plugins: [
mockDevServerPlugin({
// 录制配置
record: {
enabled: true, // 启用录制功能
dir: 'mock/.recordings', // 录制数据存储目录
overwrite: true, // 覆盖已有录制数据
expires: 0, // 录制数据过期时间(秒)
status: [], // 需要录制的状态码
filter: { // 请求过滤配置
mode: 'glob',
include: ['/api/**'],
exclude: ['/api/auth/**']
},
gitignore: true // 添加.gitignore
},
// 回放配置(可选,默认开启)
replay: true
})
],
server: {
proxy: {
'/api': 'http://localhost:8080' // 后端服务地址
}
}
})配置选项
record.enabled
- 类型:
boolean - 默认:
false - 说明:是否启用录制功能。设为
true时,插件会自动记录通过Proxy转发的请求响应。
record.dir
- 类型:
string - 默认:
'mock/.recordings' - 说明:录制数据存储目录,路径相对于项目根目录。插件会自动创建该目录。
record.overwrite
- 类型:
boolean - 默认:
true - 说明:是否覆盖已有录制数据。
true:相同请求的新响应会覆盖旧数据false:保留旧数据,不记录新数据
record.expires
- 类型:
number - 默认:
0 - 说明:录制数据过期时间(秒)。
0:永不过期- 正数:指定秒数后过期,录制新数据时会自动清理过期数据
record.status
- 类型:
number | number[] - 默认:
[] - 说明:需要录制的HTTP状态码。
- 空数组:记录所有状态码
- 指定状态码:仅记录指定状态码
record.filter
- 类型:
((req: RecordedReq) => boolean) | { include?: string | string[], exclude?: string | string[], mode: 'glob' | 'path-to-regexp' } - 默认:记录所有请求
- 说明:过滤需要记录的请求。
函数模式:
ts
export default {
record: {
filter: (req) => {
// 仅记录GET请求
return req.method === 'GET'
}
}
}对象模式:
ts
export default {
record: {
filter: {
mode: 'glob', // 或'path-to-regexp'
include: ['/api/**'], // 包含路径
exclude: ['/api/auth/**'] // 排除路径
}
}
}record.gitignore
- 类型:
boolean - 默认:
true - 说明:是否在录制目录自动添加
.gitignore文件(内容:*),防止录制数据意外提交至版本控制。
replay
- 类型:
boolean - 默认:
true(当record.enabled为true时) - 说明:是否启用回放功能。可独立控制回放,例如仅回放不录制:
ts
export default {
record: { enabled: false }, // 不录制新数据
replay: true // 但使用已有录制数据
}录制文件
存储结构
录制数据默认存储在mock/.recordings/目录下,按请求路径组织:
txt
项目根目录/
├── mock/
│ ├── .recordings/ # 录制数据目录
│ │ ├── .gitignore # 自动生成的gitignore文件
│ │ ├── api-users.json # GET /api/users的录制数据
│ │ ├── api-users-id.json # GET /api/users/:id的录制数据
│ │ └── api-login.json # POST /api/login的录制数据
│ └── *.mock.ts # mock文件
└── vite.config.ts文件命名规则
录制文件使用请求路径的kebab-case格式命名:
txt
规则:{kebab-case(pathname)}.json
示例:
- /api/users → api-users.json
- /api/users/:id → api-users-id.json
- /api/user/profile → api-user-profile.json文件内容格式
json
[
{
"meta": {
"timestamp": 1704067200000,
"createAt": "2024/1/1 00:00:00",
"filepath": "mock/.recordings/api-users.json",
"referer": "http://localhost:5173/"
},
"req": {
"method": "GET",
"pathname": "/api/users",
"query": { "page": "1", "size": "10" },
"body": null,
"bodyType": ""
},
"res": {
"status": 200,
"statusText": "OK",
"headers": {
"content-type": "application/json"
},
"body": "[{\"id\":1,\"name\":\"John\"}]"
}
}
]数据结构说明
meta - 元数据
| 字段 | 类型 | 说明 |
|---|---|---|
timestamp | number | 录制时间戳(毫秒) |
createAt | string | 格式化的录制时间 |
filepath | string | 录制文件路径 |
referer | string | 请求来源页面 |
req - 请求数据
| 字段 | 类型 | 说明 |
|---|---|---|
method | string | HTTP方法(GET/POST/PUT/DELETE等) |
pathname | string | 请求路径 |
query | object | URL查询参数 |
body | unknown | 请求体数据 |
bodyType | string | 请求体类型(如application/json) |
res - 响应数据
| 字段 | 类型 | 说明 |
|---|---|---|
status | number | HTTP状态码 |
statusText | string | 状态文本 |
headers | object | 响应头(已过滤动态头) |
body | string | 响应体(文本UTF-8,二进制Base64) |
响应头过滤
录制时会自动过滤以下动态或环境相关的响应头,确保录制数据的可移植性:
过滤的响应头类别
日期时间相关(每次请求变化)
date,expires,last-modified
服务器信息(环境相关)
server,x-powered-by,x-aspnet-version,x-nginx-version,via
缓存控制(回放时不需要)
cache-control,etag,age
连接相关(回放环境不同)
connection,keep-alive,proxy-authenticate,proxy-authorization
CORS相关(回放环境不同)
access-control-allow-origin,access-control-allow-credentials等
动态标识符(每次请求唯一)
x-request-id,x-correlation-id,x-trace-id,cf-ray等
请求匹配机制
回放时使用精确匹配算法判断是否使用录制数据:
匹配条件
两个请求被视为相同的条件:
- 相同pathname -
pathname完全匹配 - 相同HTTP方法 -
method匹配 - 相同body类型 -
bodyType匹配 - 相同查询参数 -
query深度相等 - 相同body -
body深度相等(Buffer使用字节比较)
匹配示例
txt
// 录制时的请求
{
method: 'GET',
pathname: '/api/users',
query: { page: '1', size: '10' },
body: null
}
// 此请求会匹配
{
method: 'GET',
pathname: '/api/users',
query: { page: '1', size: '10' },
body: null
}
// 此请求不会匹配(查询参数不同)
{
method: 'GET',
pathname: '/api/users',
query: { page: '2', size: '10' },
body: null
}使用示例
示例1:基础用法
ts
// vite.config.ts
import { defineConfig } from 'vite'
import { mockDevServerPlugin } from 'vite-plugin-mock-dev-server'
export default defineConfig({
plugins: [
mockDevServerPlugin({
prefix: ['/api'],
record: true // 一键开启录制与回放
})
],
server: {
proxy: {
'/api': 'http://localhost:8080'
}
}
})示例2:按状态码过滤
ts
// vite.config.ts
import { defineConfig } from 'vite'
import { mockDevServerPlugin } from 'vite-plugin-mock-dev-server'
export default defineConfig({
plugins: [
mockDevServerPlugin({
prefix: ['/api'],
record: {
enabled: true,
status: [200, 201], // 仅记录成功响应
overwrite: true
}
})
]
})示例3:使用Glob过滤请求
ts
// vite.config.ts
import { defineConfig } from 'vite'
import { mockDevServerPlugin } from 'vite-plugin-mock-dev-server'
export default defineConfig({
plugins: [
mockDevServerPlugin({
prefix: ['/api'],
record: {
enabled: true,
filter: {
mode: 'glob',
include: ['/api/users/**', '/api/orders/**'], // 仅记录用户和订单API
exclude: ['/api/users/sensitive/**'] // 排除敏感API
}
}
})
]
})示例4:使用path-to-regexp过滤
ts
// vite.config.ts
import { defineConfig } from 'vite'
import { mockDevServerPlugin } from 'vite-plugin-mock-dev-server'
export default defineConfig({
plugins: [
mockDevServerPlugin({
prefix: ['/api'],
record: {
enabled: true,
filter: {
mode: 'path-to-regexp',
include: ['/api/:resource/:id'], // 匹配/api/users/123
exclude: ['/api/auth/:action'] // 排除鉴权相关
}
}
})
]
})示例5:自定义过滤函数
ts
// vite.config.ts
import { defineConfig } from 'vite'
import { mockDevServerPlugin } from 'vite-plugin-mock-dev-server'
export default defineConfig({
plugins: [
mockDevServerPlugin({
prefix: ['/api'],
record: {
enabled: true,
filter: (req) => {
// 仅记录GET请求且不包含敏感信息的路径
return req.method === 'GET' && !req.pathname.includes('sensitive')
}
}
})
]
})示例6:设置过期时间
ts
// vite.config.ts
import { defineConfig } from 'vite'
import { mockDevServerPlugin } from 'vite-plugin-mock-dev-server'
export default defineConfig({
plugins: [
mockDevServerPlugin({
prefix: ['/api'],
record: {
enabled: true,
expires: 86400, // 录制数据24小时后过期
overwrite: true
}
})
]
})示例7:仅回放不录制
ts
// vite.config.ts
import { defineConfig } from 'vite'
import { mockDevServerPlugin } from 'vite-plugin-mock-dev-server'
export default defineConfig({
plugins: [
mockDevServerPlugin({
prefix: ['/api'],
record: { enabled: false }, // 不录制新数据
replay: true // 但使用已有录制数据
})
]
})示例8:自定义存储目录
ts
// vite.config.ts
import { defineConfig } from 'vite'
import { mockDevServerPlugin } from 'vite-plugin-mock-dev-server'
export default defineConfig({
plugins: [
mockDevServerPlugin({
prefix: ['/api'],
record: {
enabled: true,
dir: 'recordings/api', // 自定义存储目录
overwrite: false, // 不覆盖已有录制
gitignore: false // 不自动生成.gitignore
}
})
]
})最佳实践
1. 开发阶段策略
txt
早期开发(后端未就绪)
↓ 使用模拟数据进行快速开发
集成阶段(后端就绪)
↓ 开启录制功能捕获真实响应
稳定阶段(后端稳定)
↓ 可关闭录制,使用录制数据或模拟数据2. 团队协作规范
- 录制核心接口:将关键业务接口的录制文件提交版本管理
- 敏感数据处理:避免录制包含敏感信息的接口(如登录、支付)
- 定期更新:周期性重新录制以同步后端接口变更
3. 版本控制建议
sh
# .gitignore
# 插件默认自动添加,如需手动配置:
mock/.recordings/*
!mock/.recordings/.gitkeep提交录制数据至版本控制:
ts
// vite.config.ts
export default {
record: {
enabled: true,
gitignore: false // 禁止自动生成.gitignore
}
}4. 性能优化
- 录制性能影响极小,仅在Proxy响应时保存数据
- 使用
filter配置仅录制必要请求 - 设置合理的
expires时间自动清理过期数据
5. 安全注意事项
- 避免录制含敏感信息的接口(密码、令牌、个人信息等)
- 使用
filter.exclude排除敏感路径 - 录制文件默认被
.gitignore排除,防止误提交
常见问题
Q: 为什么没有生成录制文件?
可能原因:
- 未设置
record.enabled=true - 请求未经过Proxy(Mock匹配优先)
- 请求被
filter过滤 - 响应状态码不符合
status配置
排查方法:
ts
export default {
record: {
enabled: true,
filter: (req) => {
console.log('录制请求:', req.pathname)
return true // 临时返回true测试
}
}
}Q: 为什么录制的数据没有回放?
可能原因:
replay设为false- 录制数据已过期(超过
expires设置) - 请求匹配失败(路径、参数或Body不匹配)
- Mock数据匹配成功(Mock优先级更高)
Q: 如何清理全部录制数据?
直接删除录制目录:
bash
rm -rf mock/.recordings或在配置中设置1秒过期后重新录制:
ts
export default {
record: {
enabled: true,
expires: 1 // 1秒后过期
}
}Q: 录制数据占用空间过大怎么办?
- 使用
filter仅录制必要接口 - 设置合理的
expires时间 - 定期手动清理录制目录
- 避免录制返回大文件的接口
Q: 是否支持WebSocket录制?
当前版本不支持WebSocket请求的录制与回放,仅支持HTTP/HTTPS请求。
与其他功能的关系
与Mock数据的优先级
Mock数据 > 录制数据 > 代理转发
ts
// 如果mock文件中有匹配配置
export default defineMock({
url: '/api/users',
body: { list: [] } // Mock数据优先
})
// 即使存在录制数据,也会使用上述Mock配置与代理配置的关系
录制功能依赖Vite的server.proxy配置:
ts
export default defineConfig({
plugins: [
mockDevServerPlugin({
record: true
})
],
server: {
proxy: {
'/api': 'http://localhost:8080' // 录制会拦截此代理
}
}
})与构建功能的集成
构建独立Mock服务时可选择包含录制文件:
ts
mockDevServerPlugin({
record: { enabled: true },
build: {
includeRecord: true // 构建产物包含录制文件
}
})