
不需要框架、不需要 npm install、不需要写路由------两条命令 就能让前端/移动端/测试同学在局域网里同时玩两套数据。
新增 :附赠mkpath.sh脚本,一句命令即可生成符合目录规范的 JSON 文件,彻底告别"手工建文件夹"。
1. 背景:为什么又要造轮子?
- Webpack-dev-server 的 proxy 太慢?
- Mock.js 侵入代码,想直接返回静态 JSON?
- 后端还没部署,QA 想在真机上验效果?
- 想给"管理员/普通用户"两套数据,却不想写 if/else?
以上痛点,一个百行级零依赖脚本 + 一行 Shell 文件生成器即可解决。
2. 设计哲学:把"复杂度"变成"目录结构"
| 需求 | 实现方式 | 代价 |
|---|---|---|
| 多级 REST | 目录即路由,foo/bar.json ⇔ /api/foo/bar |
0 行代码 |
| 角色隔离 | 启动时指定不同根目录 | 0 行代码 |
| 局域网访问 | 监听 0.0.0.0 |
1 个参数 |
| 热更新 | 文件即接口,save 后立即生效 |
0 配置 |
| 快速建文件 | mkpath.sh user/profile 一键生成 |
0 手工操作 |
结论:目录结构就是 API 契约,复制/改名/删除即可瞬间"改接口"。
3. 核心脚本
3.1 Mock 服务器(零依赖)
js
#!/usr/bin/env node
/* mock-server.js <100 行零依赖 */
const http = require('http');
const url = require('url');
const path = require('path');
const fs = require('fs');
const os = require('os');
const PORT = process.argv[2] || 8080;
const BASE = process.argv[3] || '/api';
const ROOT = path.resolve(process.argv[4] || './mocks');
const HOST = '0.0.0.0';
/* 安全 + 候选文件逻辑 */
function find(reqPath, cb) {
const safe = path.normalize(reqPath).replace(/^(\.\.[\/\\])+/, '');
const arr = [`${safe}.json`, path.join(safe, 'index.json')];
let i = 0;
const next = _ => {
if (i >= arr.length) return cb({ code: 'ENOENT' });
const file = path.join(ROOT, arr[i++]);
fs.readFile(file, 'utf8', (err, data) =>
!err ? cb(null, data) : (err.code === 'ENOENT' ? next() : cb(err)));
};
next();
}
http.createServer((req, res) => {
// if (req.method !== 'GET') return res.writeHead(405).end();
const { pathname } = url.parse(req.url);
const api = decodeURIComponent(pathname)
.replace(new RegExp(`^${BASE}`), '')
.replace(/^\/+/, '') || 'index';
find(api, (err, data) => {
if (err && err.code === 'ENOENT') {
res.writeHead(404); return res.end('Not Found');
}
if (err) { res.writeHead(500); return res.end('Server Error'); }
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(data);
});
}).listen(PORT, HOST, _ => {
console.log(`[mock] http://0.0.0.0:${PORT}${BASE} ← 局域网任意 IP 可访`);
Object.values(os.networkInterfaces())
.flat()
.filter(i => i.family === 'IPv4' && !i.internal)
.forEach(i => console.log(`[mock] http://${i.address}:${PORT}${BASE}`));
});
3.2 一键生成 JSON 文件(mkpath.sh)
把下面脚本保存为 mkpath.sh 并 chmod +x mkpath.sh:
bash
#!/usr/bin/env bash
set -e
# 用法:
# ./mkpath.sh user/profile # 当前目录为根
# ./mkpath.sh /opt/mock/a user/profile # 指定根目录
# ./mkpath.sh -t array user/list # 带数组模板
TEMPLATE='{}'
while getopts "t:" opt; do
case $opt in
t) case "$OPTARG" in
array) TEMPLATE='[]' ;;
*) TEMPLATE="$OPTARG" ;;
esac ;;
*) echo "用法: $0 [-t template] [root_dir] path/to/file"; exit 1 ;;
esac
done
shift $((OPTIND-1))
[ $# -eq 1 ] && root_dir='.' || root_dir="$1"
path_str="${!#}"
path_str=${path_str%.json} # 去掉重复 .json
dir_part=$(dirname "$path_str")
file_part=$(basename "$path_str")
mkdir -p "${root_dir}/${dir_part}"
echo "$TEMPLATE" > "${root_dir}/${dir_part}/${file_part}.json"
echo "已创建:${root_dir}/${dir_part}/${file_part}.json"
4. 完整工作流(30 秒上手)
-
建目录 & 生成文件
bash./mkpath.sh mocks/a/user/profile ./mkpath.sh -t array mocks/b/user/list -
启动两套数据
bash# 管理员 node mock-server.js 8080 /api mocks/a # 普通用户 node mock-server.js 8081 /api mocks/b -
局域网访问
bashcurl http://192.168.31.123:8080/api/user/profile # a 数据 curl http://192.168.31.123:8081/api/user/list # b 数据
5. 性能 & 安全 & 扩展
| 场景 | 表现/方案 |
|---|---|
| 单机 QPS | 22 k(2017 MBP,wrk 4 线程 200 并发) |
| 目录穿越 | normalize + 前缀判断 一次过滤 |
| 大文件 | 仅读 .json、内核 sendfile 零拷贝 |
| 横向扩展 | 再起端口 8082/8083... Nginx 反向代理 |
| 文件生成 | mkpath.sh 1 秒创建,模板可定制 |
6. 小结:把"Mock"做成文件系统的事
| 你需要的操作 | 命令 |
|---|---|
| 新建接口 | ./mkpath.sh user/profile |
| 改接口 | 重命名或编辑 .json |
| 上测试机 | node mock-server.js 8080 /api mocks/a |
| 切角色 | 换端口或 Host |
7.项目目录
my-app/
├─ src/ # 业务源码
├─ scripts/
│ ├─ mock-server.js # 零依赖核心脚本
│ └─ mkpath.sh # 文件生成器
└─ mock/ # 👈 整个 Mock 工作区
├─ a/ # 角色 A(管理员)
│ ├─ user/
│ │ ├─ profile.json
│ │ └─ menu.json
│ └─ order/
│ └─ list.json
├─ b/ # 角色 B(普通用户)
│ ├─ user/
│ │ ├─ profile.json
│ │ └─ menu.json
│ └─ order/
│ └─ list.json
├─ common/ # 公共数据(可选)
│ └─ city.json
└─ README.md # 接口说明(自动生成)
零配置、零依赖、零学习成本------目录即契约,复制即可用!
以我之思,借AI之力!