{T}

JSON Server 实战指南

概述

JSON Server 是一个零配置的 RESTful API 模拟服务,仅需一个 JSON 文件即可在数秒内启动一个支持完整 CRUD、过滤、分页、排序的 HTTP 服务。相比 Mock.js 的浏览器端拦截,JSON Server 提供真实的网络请求体验,适合多人协作和需要持久化数据的开发场景。

前置知识

学习目标

  • 掌握 JSON Server 的 RESTful 查询能力(过滤、分页、排序、关联)
  • 能够编写自定义中间件扩展服务行为
  • 掌握白名单代理实现 Mock 与真实接口共存
  • 理解 JSON Server 的适用边界与局限性

一、快速启动

1.1 安装与基本使用

bash
# 全局安装
npm install -g json-server

# 创建数据文件
echo '{ "posts": [{ "id": 1, "title": "Hello" }] }' > db.json

# 启动服务(默认端口 3000)
json-server --watch db.json

# 指定端口
json-server --watch db.json --port 4000

启动后自动生成以下 RESTful 端点:

方法路径说明
GET/posts获取列表
GET/posts/1获取单条
POST/posts新增
PUT/posts/1全量更新
PATCH/posts/1部分更新
DELETE/posts/1删除

1.2 数据文件结构

json
{
  "users": [
    { "id": 1, "name": "张伟", "role": "admin" },
    { "id": 2, "name": "李娜", "role": "user" }
  ],
  "courses": [
    { "id": 1, "title": "前端工程化", "userId": 1, "price": 199 },
    { "id": 2, "title": "TypeScript 实战", "userId": 2, "price": 299 }
  ],
  "comments": [
    { "id": 1, "body": "很好", "courseId": 1 }
  ]
}

顶层 key 即为资源名,自动生成对应路由。


二、RESTful 查询能力

2.1 过滤

bash
# 精确匹配
GET /courses?userId=1

# 多条件
GET /courses?userId=1&price=199

2.2 分页

bash
# _page: 页码(从1开始),_limit: 每页条数
GET /courses?_page=1&_limit=10

# 响应头包含分页信息
# X-Total-Count: 50
# Link: <http://localhost:3000/courses?_page=2&_limit=10>; rel="next"

2.3 排序

bash
# 按 price 升序
GET /courses?_sort=price&_order=asc

# 多字段排序
GET /courses?_sort=userId,price&_order=desc,asc

2.4 切片与范围

bash
# 取前 3 条
GET /courses?_start=0&_end=3

# 取第 4~6 条
GET /courses?_start=3&_limit=3

2.5 操作符

操作符示例说明
_gte / _lte?price_gte=100&price_lte=300范围查询
_ne?role_ne=admin不等于
_like?title_like=前端模糊匹配(正则)

2.6 关联查询

bash
# 获取课程及其评论(_embed 嵌入子资源)
GET /courses?_embed=comments

# 获取评论及其所属课程(_expand 展开父资源)
GET /comments?_expand=course

2.7 全文搜索

bash
# q 参数在所有字段中搜索
GET /courses?q=工程

三、自定义中间件

JSON Server 基于 Express,支持通过中间件扩展行为。

3.1 创建自定义服务

javascript
// 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((req, res, next) => {
  if (req.query._page) {
    req.query._page = parseInt(req.query._page, 10)
  }
  if (req.query._limit) {
    req.query._limit = parseInt(req.query._limit, 10)
  }
  next()
})

// 自定义中间件:CORS 增强
server.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*')
  res.header('Access-Control-Allow-Methods', 'GET,POST,PUT,PATCH,DELETE,OPTIONS')
  res.header('Access-Control-Allow-Headers', 'Content-Type,Authorization')
  if (req.method === 'OPTIONS') {
    return res.sendStatus(204)
  }
  next()
})

// 自定义中间件:模拟延迟
server.use((req, res, next) => {
  const delay = Math.random() * 400 + 100 // 100~500ms
  setTimeout(next, delay)
})

// 自定义中间件:简单认证
server.use((req, res, next) => {
  const publicPaths = ['/api/login', '/api/register']
  if (publicPaths.includes(req.path)) {
    return next()
  }
  const token = req.headers.authorization
  if (!token || token !== 'Bearer mock-token') {
    return res.status(401).json({ code: 401, message: 'Unauthorized' })
  }
  next()
})

// 自定义路由:统一响应格式
server.use('/api', (req, res, next) => {
  const originalJson = res.json.bind(res)
  res.json = (data) => {
    return originalJson({
      code: 0,
      message: 'success',
      data
    })
  }
  next()
})

server.use(router)
server.listen(3000, () => {
  console.log('JSON Server running at http://localhost:3000')
})

3.2 启动自定义服务

bash
node server.js

四、白名单代理

实际项目中,部分接口已由后端提供,需要将请求分流:

图表渲染中…

4.1 使用 http-proxy-middleware

javascript
// server.js(在自定义服务基础上添加)
const { createProxyMiddleware } = require('http-proxy-middleware')

// 白名单:这些路径代理到真实后端
const PROXY_LIST = ['/api/config', '/api/upload', '/api/payment']

PROXY_LIST.forEach((path) => {
  server.use(
    path,
    createProxyMiddleware({
      target: 'http://backend-server:8080',
      changeOrigin: true
    })
  )
})

// 其余请求由 JSON Server 处理
server.use(router)

4.2 Vite 开发代理配合

javascript
// vite.config.js
export default defineConfig({
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:3000', // JSON Server
        changeOrigin: true
      }
    }
  }
})

五、静态资源服务

JSON Server 默认可托管 public/ 目录下的静态文件:

code
project/
├── db.json
├── server.js
└── public/
    ├── images/
    │   └── avatar.png
    └── files/
        └── document.pdf

访问 http://localhost:3000/images/avatar.png 即可获取静态资源,适合模拟文件上传后的 URL 返回。


六、路由映射

当接口路径与 JSON 数据结构不一致时,使用 routes.json 进行映射:

json
{
  "/api/v1/users": "/users",
  "/api/v1/courses/:id": "/courses/:id",
  "/articles\\?category=:cat": "/posts?category=:cat"
}

启动时指定:

bash
json-server --watch db.json --routes routes.json

常见问题

问题原因解决方案
修改 db.json 后未生效未使用 --watch 参数添加 --watch 或重启服务
POST 请求返回 201 但格式不对未设置 Content-Type请求头添加 Content-Type: application/json
关联查询返回空外键命名不规范确保使用 资源名单数 + Id(如 userId
并发写入数据丢失JSON 文件非事务性存储仅用于开发环境,勿存储重要数据
自定义中间件不生效注册顺序在 router 之后确保中间件在 server.use(router) 之前注册

最佳实践

  1. 数据文件版本管理:将 db.json 纳入 Git,团队共享统一的 Mock 数据基准
  2. 中间件分层:认证、日志、延迟模拟分别独立为中间件,便于按需组合
  3. 渐进式代理:随后端接口就绪,逐步将路径加入白名单,实现平滑切换
  4. 配合 Mock.js 使用:JSON Server 提供 CRUD 骨架,复杂随机数据用 Mock.js 生成后写入 db.json
  5. 端口约定:团队统一 JSON Server 端口(如 3001),避免与开发服务器冲突

延伸阅读