Node v6下存储代理服务请求响应搭建Mock服务的可行方案有哪些?
适配Node v6的代理录制+回放方案
以下方案均兼容Node v6环境,可覆盖GET/POST/DELETE、重定向、文件传输等所有你提到的场景:
方案1:使用yakbak(开箱即用,无自定义需求首选)
yakbak是专门为HTTP代理录制回放设计的工具,3.x版本完全适配Node v6,原生处理所有HTTP协议逻辑,不需要自己处理响应解析、流消费等细节。
接入步骤
- 安装兼容版本
npm install yakbak@3.1.1
- 替换现有代理代码即可
const http = require('http'); const yakbak = require('yakbak'); // 配置原服务地址和录制文件存储目录 const proxy = yakbak('http://localhost:9000', { dirname: __dirname + '/tapes' // 所有请求响应会以哈希命名的文件存在这个目录下 }); http.createServer(proxy).listen(8999);
工作逻辑
- 首次请求没有匹配的录制文件时,会自动转发到9000端口,将完整的响应(状态码、头、body、重定向信息等)写入本地文件
- 后续相同请求进来直接读取本地文件返回,不需要再访问9000端口
- 默认按请求方法、路径、请求头、请求body的哈希做匹配规则,也支持自定义匹配逻辑。所有请求录制完成后直接停用9000端口即可,8999端口可独立作为Mock服务运行。
方案2:使用nock录制能力(适合需要自定义存储的场景)
如果你需要把录制内容存在数据库而非本地文件,可以用兼容Node v6的nock 9.x版本,搭配原有http-proxy使用:
接入示例
- 安装对应版本
npm install nock@9.6.1 http-proxy
- 代码实现
const http = require('http'); const proxy = require('http-proxy').createProxyServer(); const nock = require('nock'); // 开启录制模式,录制所有对外请求 nock.recorder.rec({ output_objects: true, enable_reqheaders_recording: true }); http .createServer(function (req, res) { // 检查是否有已录制的匹配请求,有就直接返回 const recorded = nock.activeMocks().find(mock => mock.match(req)); if (recorded) { return recorded.reply(res); } // 没有匹配项走代理,同时自动录制 proxy.web(req, res, { target: 'http://localhost:9000', followRedirects: false }); // 录制完成后可自定义写入数据库逻辑 const records = nock.recorder.play(); // 此处可添加数据库写入逻辑 }) .listen(8999);
方案3:基于现有http-proxy二次改造(适合高度定制场景)
如果不想引入新依赖,可以直接在现有代理逻辑上扩展,完整捕获请求和响应信息本地存储即可:
const http = require('http'); const proxy = require('http-proxy').createProxyServer(); const fs = require('fs'); const crypto = require('crypto'); // 初始化存储目录 if (!fs.existsSync('./records')) fs.mkdirSync('./records'); // 生成请求唯一标识,可自定义匹配规则 function getRequestId(req) { const hash = crypto.createHash('md5'); hash.update(req.method + req.url + JSON.stringify(req.headers) + req.body); return hash.digest('hex'); } http .createServer(function (req, res) { // 先完整接收请求体 let reqBody = []; req.on('data', chunk => reqBody.push(chunk)); req.on('end', () => { req.body = Buffer.concat(reqBody).toString(); const reqId = getRequestId(req); // 命中本地录制直接返回 if (fs.existsSync(`./records/${reqId}.json`)) { const record = JSON.parse(fs.readFileSync(`./records/${reqId}.json`, 'utf8')); res.writeHead(record.statusCode, record.headers); res.end(Buffer.from(record.body, 'base64')); return; } // 未命中走代理并录制响应 let resBody = []; proxy.on('proxyRes', (proxyRes) => { proxyRes.on('data', chunk => resBody.push(chunk)); proxyRes.on('end', () => { const fullBody = Buffer.concat(resBody); const record = { statusCode: proxyRes.statusCode, headers: proxyRes.headers, // 二进制内容转base64存储避免乱码 body: fullBody.toString('base64') }; fs.writeFileSync(`./records/${reqId}.json`, JSON.stringify(record)); }); }); // 把已消费的请求体塞回流中供代理使用 req.unshift(Buffer.from(req.body)); proxy.web(req, res, { target: 'http://localhost:9000', followRedirects: false }); }); }) .listen(8999);
注意事项
上述所有依赖版本均已锁定适配Node v6,不要安装最新版,避免出现语法不兼容问题。
内容的提问来源于stack exchange,提问作者Erik Kránicz
相关产品推荐
相关产品推荐

