从前端 React 到后端 NestJS,一套基于 Mockjs 的全链路"摸鱼"指南(不是,是提效指南)。
开篇:那个深夜,我和后端的"爱恨情仇"
还记得那个周五的晚上吗?你兴致勃勃地打开了 VS Code,准备大干一场,写一个惊天地泣鬼神的管理后台。你设计好了页面,配置好了路由,甚至把 axios 都 import 进来了。
然后,你兴冲冲地去找后端小哥:"哥,把用户列表接口给我,我要联调了!"
后端小哥头也不抬,冷冷地回了一句:"忙着呢,实体类还没建好,JWT 鉴权还没写完,Redis 缓存还没配,下周一吧。"
周一??? 我的热血只在这一秒沸腾,你让我等到周一?
那一刻,我仿佛听到了产品狗在工位旁磨刀的声音。
于是,我悟了。全栈开发的第一课,不是写代码,而是学会"自给自足"。 既然你不动,那我就自己造一个"你"出来。
这就是今天我要分享的主角------Mock(模拟数据) 。
一、 Mock 是什么?是前端的"海市蜃楼",也是后端的"单元测试"
在进入正题前,我们得先统一一下价值观。
Mock 的本质,就是"欺骗"。 欺骗你的前端代码,让它以为自己正在和一个高大上的服务器进行着 500ms 的延迟交互,实际上,数据就在你本地的内存里。
它有两大核心价值:
- 前端独立开发: 不用看后端脸色,接口文档在手,天下我有。
- 后端接口自测: 在数据库还没建好时,先跑通业务逻辑。
今天,我就以一个AI 全栈项目为例,带大家看看如何在 React 前端和 NestJS 后端同时施展"影分身"之术。
二、 前端篇:Mockjs,那个能造"假"乱真的库
在 React + TypeScript 的世界里,Mockjs 是我们的老伙计。它不仅能造数据,还能造"随机"的数据。
1. 假装我们有 45 条文章数据
在项目中,我们通常会遇到分页列表。按照常规思路,我们要写一堆死数据。但在 Mock 的世界里,一行代码搞定:
javascript
// mock/posts.ts
import Mock from 'mockjs';
const tags = ["前端", "后端", "职场", "AI", "副业", "面经", "算法"];
const posts = Mock.mock({
'list|45': [ // 看好了,我要造45条数据!
{
title: '@ctitle(8, 20)', // 随机中文标题,8到20个字
brief: '@ctitle(20, 100)', // 随机中文摘要
totalComments: '@integer(1, 30)', // 随机评论数
totalLikes:'@integer(0, 500)', // 随机点赞数
publishedAt: '@datetime("yyyy-MM-dd HH:mm")', // 随机时间
user: {
name: '@cname', // 随机中文姓名
avatar: '@image(300x200)' // 连头像都是随机生成的图片链接!
},
tags: () => Mock.Random.pick(tags, 2), // 随机从数组里挑2个标签
id: '@increment(1)' // 自增ID
}
]
}).list;
技巧点拨:
@ctitle、@cname、@image这些都是 Mockjs 的"语法糖"。用它,你再也不用写const name = '张三'这种枯燥的代码了。'list|45'这种写法,直接生成一个长度为 45 的数组。分页测试?拿捏得死死的。
2. 拦截请求,返回"假"数据
有了数据,我们还得拦截前端发出来的请求。在 Vite 或 Webpack 的代理配置下,我们可以直接写一个接口路由:
arduino
// mock/posts.ts
export default [
{
url: '/api/posts',
method: 'get',
response: ({ query }) => {
const { page = '1', limit = '10' } = query;
const currentPage = parseInt(page, 10);
const size = parseInt(limit, 10);
// 1. 先算总数
const total = posts.length;
// 2. 再算切片起点
const start = (currentPage - 1) * size;
// 3. 切片终点
const end = start + size;
// 4. 截取数据
const paginatedData = posts.slice(start, end);
return {
code: 200,
msg: 'success',
items: paginatedData,
pagination: {
current: currentPage,
limit: size,
total,
totalPage: Math.ceil(total / size)
}
}
}
}
]
这就是 Mock 的核心逻辑: 接口文档怎么写的,我就怎么 mock。前端代码里,你甚至感觉不到这是一份假数据。
三、 后端篇:NestJS + Prisma,数据库还没建好?先"流"一把!
你以为 Mock 只是前端的事?错!作为全栈工程师,我们要在后端也搞点事情。
在 NestJS 项目中,我们通常使用 Prisma 作为 ORM。但在 npx prisma migrate dev 之前,我们怎么测试接口的逻辑是否通顺?比如那个酷炫的 SSE (Server-Sent Events) 流式输出?
场景: 我们正在开发一个 AI ChatBot,需要像 ChatGPT 一样逐字输出。
如果这时候去调用真实的 DeepSeek 或 OpenAI 接口,不仅慢,还费钱,网络波动还会导致测试失败。
解决方案: 在 Controller 里写一个 rawResponse,直接模拟流式输出。
typescript
// ai.controller.ts
import { Controller, Post, Req, Res, Get } from '@nestjs/common';
@Controller('api/ai')
export class AiController {
// rawResponse 用于自定义原始 HTTP 响应(如流式输出)
@Post('chat')
async chat(@Req() req, @Res() res) {
// 1. 设置响应头,告诉浏览器:我要开始流式传输了!
res.setHeader('Content-Type', 'text/plain;charset=utf-8');
res.setHeader('Transfer-Encoding', 'chunked');
res.setHeader('x-vercel-ai-data-stream', 'v1');
// 2. 模拟 AI 生成的文本
const mockText = "你好!我是你的AI助手。正在使用Mock技术假装思考中...";
// 3. 模拟逐字输出(打字机效果)
for (let i = 0; i < mockText.length; i++) {
const char = mockText[i];
// 这里模拟 ai-sdk 的格式
res.write(`0:${JSON.stringify(char)}\n`);
// 加点延迟,更有真实感
await new Promise(resolve => setTimeout(resolve, 50));
}
// 4. 结束响应
res.end();
}
}
为什么要这么做?
在 NestJS 开发中,利用 Mock 进行逻辑隔离 非常重要。你可以先把接口的结构、状态码、流式传输的逻辑跑通。等 Prisma Client 生成好了,再把里面的 mockText 替换成真实的 this.aiService.stream() 即可。
四、 进阶:Mock 的"鉴权"陷阱与绕过
在全栈项目中,最难搞的往往不是数据,而是权限校验。
比如,你的文章发布接口 POST /api/posts 加了 @UseGuards(AuthGuard('jwt'))。这时候,前端调用 Mock 接口,因为没有 Token,直接被 401 拦截了。
怎么办?两个方案:
- 环境变量开关: 在 NestJS 的 Guard 里加个判断,如果是
process.env.NODE_ENV === 'development',直接放行。 - Mock 也要有仪式感: 既然要像,那就连 Token 验证都要像。
我们可以利用 jsonwebtoken 在 Mock 接口里签发一个"万能钥匙":
javascript
// mock/auth.ts
import * as jwt from 'jsonwebtoken';
const secret = "bld1235swsad!";
export default [
{
url: '/api/auth/login',
method: 'post',
response: ({ body }) => {
const { name, password } = body;
// 假装验证用户名密码
if (name === 'admin' && password === '123456') {
// 签发一个假 Token
const token = jwt.sign(
{ user: { id: 1, name: "admin" } },
secret,
{ expiresIn: 3600 }
);
return { access_token: token, user: { id: 1, name: "admin" } };
}
return { code: 401, message: '鉴权失败' };
}
}
]
这样,你的前端在开发环境下,既能测试登录流程,又能拿到 Token 去访问受保护的接口,完美闭环。
五、 总结:做一个"善始善终"的全栈工程师
通过这篇文章,我希望你掌握了以下 Mock 核心技巧:
- 前端 Mockjs: 利用
Mock.mock()生成随机数据,利用slice实现分页,完全隔离于后端。 - 后端 NestJS: 利用
rawResponse模拟流式输出(SSE),在数据库未就位时先行开发业务逻辑。 - 全链路打通: 即使有 JWT 鉴权,也能通过 Mock 登录接口生成合法 Token,保证开发体验流畅。
最后送给大家一句话:
"磨刀不误砍柴工,Mock 好了早下班。"
不要让你的宝贵时间浪费在等待后端"修仙"或者产品经理"改需求"上。利用 Mock 技术,把命运掌握在自己手里!
如果你觉得这篇文章对你有帮助,别忘了点赞、收藏、分享三连!有任何问题,欢迎在评论区留言,我将化身"行走的 Mock 工具人"为你解答。
我是爱吃火锅的程序员,我们下期再见!
附录:文中提到的核心依赖库
为了方便大家复现,整理了一下文中全栈项目涉及的核心技术栈:
表格
| 层级 | 技术栈 | 用途 |
|---|---|---|
| 前端框架 | React + TS | 构建用户界面 |
| 前端路由 | React-Router-Dom | 实现 SPA 单页应用路由 |
| 状态管理 | Zustand | 轻量级全局状态管理 |
| 接口模拟 | Mockjs | 前端拦截请求,生成随机数据 |
| 后端框架 | NestJS | 企业级 Node.js 框架 |
| 数据库 | Prisma + PostgreSQL | ORM 与 关系型数据库 |
| 鉴权 | JWT | 用户身份令牌验证 |
| AI 工具 | LangChain/Coze | AI 业务逻辑编排 |