
前端开发里有个折磨人的阶段叫“联调等待”。后端接口还没写好前端页面已经堆了一堆代码总不能干瞪眼等接口吧JSON Server 就是来解决这个问题的。它是一个基于 Node.js 的 mock 工具只需要一个 JSON 文件几十秒就能启动一个模拟的 REST API 服务支持增删改查、过滤、排序、分页还能自定义路由规则甚至插入中间件模拟复杂逻辑。这篇文章就围绕我在实际项目里的使用笔记来写从核心原理讲到进阶玩法再到踩坑实录内容偏实操向适合正在做前后端分离开发的前端新人也适合想在团队内搭建 mock 流程的技术负责人参考。1. 为什么前端需要 mock 数据工具1.1 前后端并行开发的经典痛点在前后端分离的项目里前端和后端是并行走的。后端还在设计数据库表、调接口、修 bug前端已经把页面切完了。这时候前端要调试页面渲染、交互逻辑、状态管理没有接口数据就寸步难行。我用过几种笨办法一种是在代码里硬编码一堆假数据写一个 data.js 丢进去另一种是等后端接口写完再联调。硬编码的问题在于数据写死在代码里覆盖不了真实接口的边界情况等接上真接口还得把假数据代码删掉删不干净还会误伤线上逻辑。等接口写完再联调就更不用说了前端空窗期白白浪费项目进度一拖再拖。JSON Server 这套方案的思路就是把数据独立成文件用工具起一个真正的 HTTP 服务前端代码直接通过 axios 或 fetch 请求这个服务和后端接口的调用方式完全一致。等后端接口就绪只要把 baseURL 换一下就行前端代码几乎不用改。1.2 JSON Server 的定位一个能跑起来的假后端JSON Server 本质上就是一个 Node.js 写的小型服务器它把你提供的一个 JSON 文件当作数据库根据 REST 风格自动生成接口。官方仓库的描述是“Get a full fake REST API with zero coding in less than 30 seconds”这句话真没夸张装完依赖、写个 JSON、敲一条命令服务就起来了。它的适用场景很明确前端页面开发阶段的数据模拟原型演示和 Demo 制作前端单元测试和组件测试的接口环境后端接口尚未完成时的临时联调不适合把它当作真正的后端使用因为它没有权限体系没有复杂查询引擎数据只存在本地文件里性能也扛不住高并发。搞清楚定位才能在合适的场景里发挥它的价值。2. 环境准备与基础用法2.1 安装与启动环境要求就一个Node.js。建议 Node 版本 14 以上老版本在安装最新版 JSON Server 时可能报错我遇到过 Node 12 环境装最新版装不上的情况后来用npx json-server临时运行才缓解但长期使用还是要升级 Node。安装命令npm install -g json-server如果不想全局安装也可以装成项目的开发依赖npm install json-server --save-dev全局安装的好处是随时可以用但团队协作时建议装成项目依赖并在 package.json 的 scripts 里加一条scripts: { mock: json-server --watch db.json --port 3000 }这样别的同事拉到仓库执行npm install npm run mock就能起服务不用每个人都装全局命令。启动方式很简单json-server --watch db.json--watch参数的意思是监听 db.json 的变化文件一保存服务就自动重启数据改完立刻生效。2.2 db.json 怎么写db.json 是 JSON Server 的数据源结构上就是一个 JSON 对象对象的每一个 key 对应一个资源。{ users: [ { id: 1, name: 张三, age: 25 }, { id: 2, name: 李四, age: 30 } ], articles: [ { id: 1, title: 第一篇文章, author: 张三, published: true } ] }启动后/users会返回整个 users 数组/articles会返回 articles 数组。JSON Server 会自动把数组里的对象加上 id 字段如果你没写 id它会自动生成自增 id。这里有几个关键点资源名的命名建议用小写复数符合 REST API 的习惯数组里的每个对象建议都带 id否则后续的增删改查操作会出问题嵌套的对象结构也能保存比如每个 users 里带一个profile: {}对象但注意嵌套资源的接口路径规则后面细说2.3 基础路由规则JSON Server 的路由规则非常规整基本上遵循 RESTful 风格请求路径作用GET/users获取列表GET/users/1获取单条POST/users新增一条PUT/users/1整体更新PATCH/users/1局部更新DELETE/users/1删除一条我一开始以为 PUT 和 PATCH 差不多实际用下来发现区别很大。PUT 是把整个对象替换掉如果请求体里只传了name那这个对象的age字段就会被删掉。PATCH 则是只更新请求体里带的字段其他字段保留。前端开发时推荐优先用 PATCH更安全。3. 核心功能实操过滤、排序、分页与搜索3.1 过滤查询JSON Server 支持以_开头的特殊查询参数这部分是真正常用的。http://localhost:3000/users?name张三 http://localhost:3000/users?age25name李四上面这两种写法是基于相等条件的过滤。如果你想做范围过滤用的是_gte、_lte、_ne、_gt、_lthttp://localhost:3000/users?age_gte20 http://localhost:3000/users?age_lte30 http://localhost:3000/users?age_ne25这些参数的语意分别是年龄大于等于 20、小于等于 30、不等于 25。项目里做筛选功能非常方便不需要后端写任何逻辑前端通过 URL 参数就能模拟出筛选效果。还有一个需要注意的点多个过滤条件之间的关系是 AND。我在一个项目里试过?name张三age30返回的是同时满足两个条件的记录不是或的关系。3.2 排序排序用的是_sort和_orderhttp://localhost:3000/users?_sortage_orderasc http://localhost:3000/users?_sortage_orderdesc多字段排序的写法http://localhost:3000/users?_sortage,name_orderdesc,asc多字段排序的顺序是先按 age 降序再按 name 升序。这个功能在做排行榜、列表排序类页面时特别管用。3.3 分页分页是列表页绕不开的需求。JSON Server 默认的实现方式有两种第一种是_page和_limithttp://localhost:3000/users?_page1_limit10这个请求会返回第一页的数据每页 10 条。响应头里会有X-Total-Count表示总记录数前端可以从响应头里读取这个值来计算总页数。第二种是_start和_end也就是切片模式http://localhost:3000/users?_start0_end10_start是从第几条开始取_end是取到第几条相当于 SQL 里的 LIMIT 和 OFFSET。这种方式适合自定义分页。我实际开发中的体会是如果前端用了antd或element这类组件库分页组件通常需要 total 数量所以一般会读取X-Total-Count响应头来做判断而不是靠返回数据长度。3.4 全文搜索JSON Server 还内置了一个简单的全文搜索http://localhost:3000/users?q张q参数会在所有字段里做模糊匹配。这个功能对于简单的搜索 mock 足够用但如果你需要精确搜索某个字段还是用前面说的_gte、_lte或者自定义过滤更靠谱。4. 进阶玩法自定义路由、中间件与代码启动4.1 自定义路由规则基础路由满足不了所有场景。比如前端想要的路径是/api/v1/users但 JSON Server 默认只有/users。这时需要一个routes.json文件{ /api/v1/users: /users, /api/v1/users/:id: /users/:id }启动时加载json-server db.json --routes routes.json/api/v1/users请求会被转发到/users。这里面的:id是路径参数占位符JSON Server 会自动匹配实际值。团队项目里经常用这种方式统一 mock 接口的路径风格让前端代码在切换 mock 和真实环境时不用改路径。4.2 使用中间件模拟业务逻辑如果 mock 需要模拟更复杂的业务比如登录时校验用户名密码、错误时返回特定提错误码就需要用到中间件。中间件本质上是一个普通的 JavaScript 函数接收req、res、next三个参数运行在 JSON Server 的 HTTP 处理流程中。// middleware.js module.exports (req, res, next) { if (req.method POST req.path /login) { const { username, password } req.body; if (username admin password 123456) { res.status(200).json({ code: 0, data: { token: mock-token-abc } }); } else { res.status(401).json({ code: 401, message: 用户名或密码错误 }); } return; } next(); };启动方式json-server db.json --middlewares middleware.js这样做的好处非常明显。前端在调登录接口的时候可以验证不同账号密码的返回逻辑比如正确的返回 token错误的返回 401。等真实后端就绪只需要把 mock 的 baseURL 切换掉前端整个鉴权逻辑的分析和验证已经在这个阶段跑通了。4.3 用 Node 代码启动 JSON Server命令行方式够用但如果你想在项目里通过一个脚本启动 JSON Server或者在同一台机器上同时跑 mock 和前端开发服务器用代码启动更方便。// server.js const jsonServer require(json-server); const server jsonServer.create(); const router jsonServer.router(db.json); const middlewares jsonServer.defaults(); server.use(middlewares); server.use(jsonServer.bodyParser); server.use(router); server.listen(3000, () { console.log(JSON Server 已启动地址: http://localhost:3000); });这个方式最大的优势是灵活。你可以在启动之前挂载自己的中间件也可以把 JSON Server 嵌入到一个 Express 应用里专门处理某个前缀路径其他路径交给其他服务。这样 mock 服务既是测试工具也是整个开发环境的一部分。配合nodemon启动改动配置文件就自动重启体验非常好。4.4 静态资源托管JSON Server 还可以托管静态资源目录比如前端打包之后的 dist 目录json-server db.json --static ./dist这个功能在做纯前端演示时很有用起一个服务能同时访问页面和 mock 接口不用再挂 Nginx 或另起一个静态服务器。5. 常见问题与排查技巧实录5.1 端口被占用怎么办最常见的问题就是端口冲突。默认端口是 3000代码里经常会有多个项目或脚手架占用这个端口。解决办法有两个json-server db.json --port 4000或者让 JSON Server 自动找空闲端口json-server db.json --port 0--port 0的意思是随机选一个可用端口启动日志里会打印实际端口。不过我建议还是显式指定端口因为随机端口会让前端代理配置变得不稳定。5.2 POST 请求的提交格式使用 POST 创建数据时一定要注意请求头的 Content-Type 必须是application/json。我之前遇到一个情况请求发出去了返回的却是 400 错误排查了半天发现是 axios 默认的 Content-Type 不对数据体没有被正确解析。正确的 axios 写法axios.post(/users, { name: 王五, age: 28 }, { headers: { Content-Type: application/json } });JSON Server 内置了 bodyParser只支持 JSON 格式的请求体不支持表单格式的application/x-www-form-urlencoded。前端写习惯表单提交的同事在这里容易踩坑。5.3 修改数据后 id 不更新的问题当你 POST 创建一条数据时如果请求体里没有 idJSON Server 会基于当前数组里最大的 id 自增。但如果你手动在 db.json 里写了 id然后 POST 时没有传 id它会取当前最大 id 加 1这个符合预期。但有一个坑是如果你删除了若干条记录再新增一条时JSON Server 取的是当前数组的最大 id不是已删除记录里最大的。比如原本有 1、2、3 三条删掉 3新增的 id 是 3而不是 4。这个在实际场景里通常没什么问题但如果你后面写了依赖 id 的关联逻辑可能就需要考虑。5.4 中文字符编码JSON Server 在数据修改后会重写 db.json 文件。如果数据库里有中文字符文件保存时默认是 UTF-8一般不会乱码。我遇到过乱码的情况是在 Windows 上使用控制台日志显示中文正常但文件被某些编辑器以 GBK 编码重新保存过导致 JSON Server 解析失败。解决办法统一使用 UTF-8 编码保存文件编辑器设置成无 BOM。同时在 Windows 下启动 JSON Server建议在 package.json 的 mock 脚本里加一句mock: chcp 65001 json-server --watch db.jsonchcp 65001 是把控制台代码页切换到 UTF-8可以避免中文输出乱码。5.5 浏览器缓存导致的“没有更新”一个容易忽略的问题浏览器对 GET 请求有缓存mock 数据更新了但页面刷新后还是旧数据。排查思路是在请求 URL 后面加一个时间戳参数axios.get(/users, { params: { _t: Date.now() } });或者在启动 JSON Server 时加一个禁用缓存的响应头。比较简单的做法是写一个中间件module.exports (req, res, next) { res.setHeader(Cache-Control, no-store); next(); };这样能保证每次请求都拿到最新的 mock 数据。这个问题在开发阶段特别容易让人误以为 JSON Server 没生效其实是浏览器把响应缓存住了。5.6 嵌套资源与关联数据的关系JSON Server 支持嵌套资源的路径比如{ users: [ { id: 1, name: 张三, posts: [{ id: 1, title: 你好 }] } ] }访问/users/1/posts可以获取这个用户下的所有文章。但是注意嵌套资源的写法在更新和删除时比较别扭建议数据设计尽量扁平化不要过度嵌套。如果你需要一个用户和一个文章列表这样的一对多关系更推荐用独立资源加外键字段的方式比如 posts 里带一个userId再通过过滤查询拿到某个用户下的文章。6. 其他实用技巧与经验总结6.1 使用--watch的注意事项--watch模式下的热更新确实方便但它有个副作用它监控的是 db.json 文件的修改事件你如果手动改的时候保存得太频繁或者文件被格式化工具批量处理会导致服务反复重启。我遇到过最烦的情况是编辑器保存时自动格式化整个 JSON 文件导致 JSON Server 的重启频率异常页面接口响应时断时续。解决办法是把--watch关掉改成手动重启或者在编辑器里对 db.json 关闭自动格式化。6.2 结合前端项目使用代理转发在 Vite 或 Webpack 项目里前端开发服务器有自己的端口JSON Server 在另一个端口直接跨域请求会有 CORS 问题。JSON Server 默认开启了 CORS所以直接用没问题。但如果你想保持请求路径和线上一致通常在 vite.config.js 里配置代理export default { server: { proxy: { /api: { target: http://localhost:3000, changeOrigin: true, rewrite: (path) path.replace(/^\/api/, ) } } } };这样前端代码里请求/api/users开发服务器会自动转发到 JSON Server。联调真实接口时只要改代理目标地址代码里一个字不用动。6.3 面试角度mock 工具相关的高频问题我在整理前端面试题时发现JSON Server 经常被当成一道考察工程化能力的题目。面试官会问“后端接口还没好前端怎么调试”这个问题不是考你会不会用某个工具而是考察你有没有完整的开发链路思维。正确的回答思路是先说明前端 mock 的核心目标让前端开发和测试不被后端阻塞列举主流方案硬编码数据、Mock.js、Charles 拦截、JSON Server说明 JSON Server 的优势纯配置即可得到 REST API支持增删改查、分页、过滤、排序满足绝大多数前端交互场景结合项目经验说明如何通过中间件模拟登录鉴权、异常返回等复杂逻辑这么回答基本就展示了你从工具使用到工程落地的完整能力。6.4 为什么不建议在生产环境用 JSON ServerJSON Server 只是一个开发期的 mock 工具所有人都不要把它当作真正的后端部署到线上。原因有几个数据存储在文件中无法支撑多实例部署没有鉴权和权限控制机制查询能力有限无法处理复杂关联查询并发能力不足它的职责是帮前端把开发阶段跑起来等到联调阶段就应该切到真实接口。团队敏捷开发时这个工具能很好地发挥桥梁作用。我自己通常会在项目里保留一份 mock 环境配置用来做 UI 测试、演示、回归验证但绝对不接入生产链路。6.5 个人实操中的几点体会用了这么久 JSON Server我最大的感受是它不仅仅是“造点假数据”而是把前端从接口依赖中解放出来。以前前端开发被动等接口现在可以先把接口结构定义好前端按约定开发后端按约定实现两边反而是并行推进的。建议你可以把 db.json 当成接口文档的“可运行版本”。后端把字段结构定义清楚前端就按这个结构去调用和渲染而有争议的字段或返回格式直接在 db.json 里 mock 出来前后端对着数据讨论比口头说字段名清楚得多。最后补充一点团队协作时在 README 里写清楚 mock 服务的启动方式和对接规范能让新同事少踩很多坑。配置文件本身不复杂但没文档的时候出了问题每个人的排查方向都不一样反而浪费时间。数据文件里放几条有代表性的假数据把边界情况也加进去价值远超过随随便便塞几个对象。