跳转到内容

请求录制与回放

功能概述

请求录制与回放是 vite-plugin-mock-dev-server 提供的高级功能,允许开发者在开发过程中自动捕获真实后端API响应,并在后续开发中回放这些录制数据。该功能提供"一次录制,随时使用"的mock数据方案,有效解决后端服务不稳定或尚未就绪时的开发痛点。

核心价值

  • 降低前后端依赖:后端服务未就绪时,前端可基于录制的真实数据进行开发
  • 提升开发稳定性:后端服务不稳定或不可用时,使用录制数据保障开发连续性
  • 便于团队协作:录制的真实数据可在团队内共享,统一开发环境
  • 简化API对接:录制真实响应后,前端调试可不重复请求后端

使用场景

场景1:后端服务未就绪

项目开发初期,后端API接口可能尚未开发完成。此时:

  1. 先使用mock数据进行前端页面开发
  2. 后端接口就绪后开启录制,捕获真实响应
  3. 后续开发可直接使用录制的真实数据,无需等待后端服务

场景2:后端服务不稳定

当后端服务偶发不可用、响应缓慢或返回不一致数据时:

  1. 在服务稳定时录制关键API的响应数据
  2. 服务不稳定时自动切换至录制数据回放模式
  3. 保障前端开发的连续性和稳定性

场景3:团队协作与数据共享

团队成员需要统一的mock数据环境:

  1. 录制关键业务接口的真实响应数据
  2. 将录制文件提交至版本控制系统
  3. 其他成员可直接使用录制数据进行开发

场景4:离线开发与演示

需要在无网络环境工作或进行演示时:

  1. 提前录制所需API的响应数据
  2. 离线状态下使用录制数据进行开发和演示
  3. 保障演示环境的数据稳定性和一致性

工作流程

三阶段工作流

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.enabledtrue时)
  • 说明:是否启用回放功能。可独立控制回放,例如仅回放不录制:
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 - 元数据

字段类型说明
timestampnumber录制时间戳(毫秒)
createAtstring格式化的录制时间
filepathstring录制文件路径
refererstring请求来源页面

req - 请求数据

字段类型说明
methodstringHTTP方法(GET/POST/PUT/DELETE等)
pathnamestring请求路径
queryobjectURL查询参数
bodyunknown请求体数据
bodyTypestring请求体类型(如application/json)

res - 响应数据

字段类型说明
statusnumberHTTP状态码
statusTextstring状态文本
headersobject响应头(已过滤动态头)
bodystring响应体(文本UTF-8,二进制Base64)

响应头过滤

录制时会自动过滤以下动态或环境相关的响应头,确保录制数据的可移植性:

过滤的响应头类别

  1. 日期时间相关(每次请求变化)

    • date, expires, last-modified
  2. 服务器信息(环境相关)

    • server, x-powered-by, x-aspnet-version, x-nginx-version, via
  3. 缓存控制(回放时不需要)

    • cache-control, etag, age
  4. 连接相关(回放环境不同)

    • connection, keep-alive, proxy-authenticate, proxy-authorization
  5. CORS相关(回放环境不同)

    • access-control-allow-origin, access-control-allow-credentials
  6. 动态标识符(每次请求唯一)

    • x-request-id, x-correlation-id, x-trace-id, cf-ray

请求匹配机制

回放时使用精确匹配算法判断是否使用录制数据:

匹配条件

两个请求被视为相同的条件:

  1. 相同pathname - pathname完全匹配
  2. 相同HTTP方法 - method匹配
  3. 相同body类型 - bodyType匹配
  4. 相同查询参数 - query深度相等
  5. 相同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: 为什么没有生成录制文件?

可能原因

  1. 未设置record.enabled=true
  2. 请求未经过Proxy(Mock匹配优先)
  3. 请求被filter过滤
  4. 响应状态码不符合status配置

排查方法

ts
export default {
  record: {
    enabled: true,
    filter: (req) => {
      console.log('录制请求:', req.pathname)
      return true // 临时返回true测试
    }
  }
}

Q: 为什么录制的数据没有回放?

可能原因

  1. replay设为false
  2. 录制数据已过期(超过expires设置)
  3. 请求匹配失败(路径、参数或Body不匹配)
  4. Mock数据匹配成功(Mock优先级更高)

Q: 如何清理全部录制数据?

直接删除录制目录:

bash
rm -rf mock/.recordings

或在配置中设置1秒过期后重新录制:

ts
export default {
  record: {
    enabled: true,
    expires: 1 // 1秒后过期
  }
}

Q: 录制数据占用空间过大怎么办?

  1. 使用filter仅录制必要接口
  2. 设置合理的expires时间
  3. 定期手动清理录制目录
  4. 避免录制返回大文件的接口

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 // 构建产物包含录制文件
  }
})

基于 MIT 许可发布