Mock 模块开发与项目集成
以下内容对React_Ts项目中的Mock服务二次开发与Mock配置进行说明,实现模块开发方式、工具函数、配置说明与项目接入方式。如需进行代码对照,可参考目录下 react19_ts 项目内实际代码,文档与代码会在git上持续补充
git仓库地址:https://gitee.com/xiaoli-account/react19_ts
如需先了解服务定位、目录结构、启动方式和热重载原理
请先阅读 上一篇 【React_TS 学习笔记(2-12)Mock 总览与运行机制】
目录
Mock 模块开发与项目集成/├── 一、开发定位/│ ├── 1.1 这份文档解决什么问题│ └── 1.2 当前开发约定├── 二、模块开发指南/│ ├── 2.1 模块文件结构│ ├── 2.2 响应类型/│ │ ├── 静态响应│ │ └── 动态响应│ └── 2.3 注册新模块├── 三、工具函数库/│ ├── 3.1 common.js - 通用工具│ ├── 3.2 captcha.js - 验证码工具│ └── 3.3 sm4.js - 加密工具├── 四、配置说明/│ ├── 4.1 API 路径前缀│ └── 4.2 统一响应模板├── 五、项目集成/│ ├── 5.1 react19_ts前端项目根目录联合启动脚本│ └── 5.2 前端代理与环境变量├── 六、最佳实践└── 七、常见问题
一、开发定位
1.1 这份文档解决什么问题
当你已经确认 Mock 服务可以正常启动之后,日常更常遇到的问题通常是:
这份文档就是围绕这些开发动作展开的。
1.2 当前开发约定
基于 mock/ 目录当前实现,新增或维护接口时建议遵循以下约定:
| |
|---|
| |
| |
| 分页、内存存储、验证码、加密等不要在模块内重复实现 |
| 优先使用 config/response.js 中的模板 |
| |
二、模块开发指南
2.1 模块文件结构
当前每个模块文件遵循统一导出结构:导出一个数组,数组中每项是一个“接口集合对象”,对象的 key 为实际接口路径。
示例:
const { success200 } = require("../config/response");const { API_BEFORE_URL } = require("../config/api-url");const Mock = require("mockjs");module.exports = [ { [API_BEFORE_URL + "/example/list"]: { method: "get", response: { ...success200, data: Mock.mock({ "list|10": [ { id: "@id", name: "@cname", }, ], }), }, }, [API_BEFORE_URL + "/example/detail"]: { method: "get", response: (req) => { const { id } = req.query; return { ...success200, data: { id, name: `Item ${id}` }, }; }, }, },];
2.2 响应类型
静态响应
适合“只想快速给前端一份固定结构数据”的场景。
response: { ...success200, data: Mock.mock({ "list|10": [{ id: "@id" }], }),}
动态响应
适合“需要读取请求参数、做条件分支、模拟业务校验”的场景。
response: (req) => { const { page = 1, size = 10 } = req.query; return { ...success200, data: { list: [], pagination: { page, size, total: 100 }, }, };}
2.3 注册新模块
新增一个模块的最小步骤如下:
- 在
mock/module/ 新建文件,例如 product.js - 在
mock/module/index.js 中引入并注册
示例:
const product = require("./product");function setupMock(app) { registerMockModule(app, [ login, user, role, product, ]);}
如果你只新增了文件、但忘记在 module/index.js 注册,接口不会被 Express 挂上去,这是新增模块最常见的问题之一。
三、工具函数库
3.1 common.js - 通用工具
mock/utils/common.js 主要负责请求参数处理、分页、内存存储和常见模拟数据生成。当前导出的主要工具包括:
| |
|---|
| |
| |
| createMemoryStore(initialList, options) | |
| createPageData(list, params) | |
| 格式化日期时间为 yyyy-MM-dd HH:mm:ss |
| |
| |
| matchText(value, keyword) | |
| |
| mockCnLabel(prefix, min, max) | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
- 列表接口:
createMemoryStore() + createPageData() - 请求参数解析:
getRequestData(req)
3.2 captcha.js - 验证码工具
mock/utils/captcha.js 当前已经被抽离为公共验证码工具,适合多个认证相关模块复用。
| |
|---|
| 生成新的图形验证码,返回 captchaId 、图片与答案 |
| normalizeCaptchaAnswer(value) | |
| |
| getCaptchaRecord(captchaId) | |
| |
| |
典型用法:
- 获取验证码接口:调用
createCaptcha() - 校验成功或过期后:调用
deleteCaptcha()
3.3 sm4.js - 加密工具
mock/utils/sm4.js 提供与前端保持一致的 SM4 加解密能力,目前导出:
| |
|---|
encryptBySm4(data) | |
decryptBySm4(data) | |
当前主要用途是:
- 保证 mock 登录流程和前端登录加密逻辑保持一致
四、配置说明
4.1 API 路径前缀
mock/config/api-url.js 当前内容为:
export const API_BEFORE_URL = "";
这表示 Mock 服务自身注册接口时,当前不追加额外前缀。例如:
[API_BEFORE_URL + "/login"]: { ... }
最终注册路径就是:
需要特别区分的是:
所以浏览器访问和服务实际注册路径并不相同,但这正是代理层负责解决的事情。
4.2 统一响应模板
mock/config/response.js 当前提供:
export const success200 = { code: 200, message: "操作成功", success: true,};export const success0 = { code: 0, message: "操作成功", success: true,};export const error500 = { code: 500, message: "操作失败", success: true,};
五、项目集成
5.1 react19_ts 前端项目根目录联合启动脚本
项目 react19_ts 前端项目根目录通过 mock.startup.script.js 统一启动前端和 Mock 服务:
// 启动前端const web = run("WEB", "npm run dev:mock");// 启动 Mock 服务const mockjs = run("mock", "npm --prefix mock run mock");
因此在 react19_ts 前端项目根目录执行:
实际效果是:
mock/子项目启动带热重载的 Express 服务Ctrl + C 时两个进程一起关闭
5.2 前端代理与环境变量
当前 .env.mock 中的关键配置是:
VITE_API_BASE_URL=/mock-apiVITE_APP_API_URL=http://localhost:3000
它的实际链路是:
浏览器请求: /mock-api/login ↓Vite 代理转发 ↓http://localhost:3000/login
因此如果你在联调时看到:
- Mock 服务注册地址是
/login、/userInfo 这类裸路径
这并不冲突,而是当前实现的正常表现。
六、最佳实践
- 模块里只保留业务逻辑,通用逻辑优先下沉到
utils/。 - 列表接口优先复用
createMemoryStore() 与 createPageData(),不要每次手写分页。 - 请求参数尽量统一通过
getRequestData(req) 解析,减少 GET / POST 分支判断。 - 验证码、SM4 解密这类跨模块逻辑不要重复实现,优先复用公共工具。
- 当模块超过单文件可维护范围时,例如大于 300 行,建议考虑按领域或能力创建模块目录,而后将模块内容再次细节拆分。
- 改完接口后优先观察
mock-watch 日志,确认服务确实完成了重启。
七、常见问题
Q: 新增模块文件后接口不生效?A: 先检查是否已经在 mock/module/index.js 中引入并注册。只创建文件但没注册,Express 不会自动挂载。
Q: 我明明访问的是 /mock-api/login,为什么 Mock 模块里写的是 /login?A: 因为 /mock-api 是前端代理前缀,不是 Mock 服务自身的接口前缀。当前 API_BEFORE_URL 为空字符串,所以服务内部实际注册的是 /login。
Q: 如何模拟带参数的动态响应?A: 使用函数式 response: (req) => { ... },并通过 req.query、req.body 或 getRequestData(req) 读取参数。
Q: 如何快速做一个可增删改查的列表模块?A: 优先从 createMemoryStore() 入手,再结合 createPageData() 处理分页;这比在模块里手写数组操作更稳定也更统一。