在前后端分离开发里,接口Mock早就是常规操作,但大部分Mock方案只解决了JSON数据的伪造,图片类型的响应往往被跳过。前端在做轮播图、头像上传预览、懒加载占位时,如果Mock层只能给一个图片URL字符串,真实请求打过去还是404,组件里的onerror、loading状态根本走不通。用Node.js搭一个Koa服务,在中间件里直接画出图片并返回,是补齐这块短板的最轻量做法。Koa本身没有内置路由和图片库,靠它极简的中间件栈,我们完全可以只用核心模块加少量代码完成。

基础服务搭建与中间件结构
先用npm初始化一个项目并安装koa,不需要额外装koa-router也能写简单路由,因为我们可以通过ctx.path来判断请求路径。Koa的入口就是一个new Koa()实例,然后用app.use注册异步函数,每个中间件拿到ctx和next。在Mock图片的场景下,我们通常会写一个前置中间件,专门拦截以/mock/img开头的请求,根据查询参数决定返回什么图。
这种结构的优势在于不影响其他JSON接口的Mock。比如你已有JSON假数据中间件,只要把图片中间件放在前面并用await next()控制流转,就能让两类Mock共存。Koa的洋葱模型保证请求依次进入、响应依次退出,我们在图片中间件里若已赋值ctx.body,直接return即可短路后续逻辑,避免多余处理。下面是一段最小可用骨架:
const Koa = require('koa');
const app = new Koa();
app.use(async (ctx, next) => {
if (ctx.path.startsWith('/mock/img')) {
// 稍后填充图片逻辑
return;
}
await next();
});
app.use(async (ctx) => {
ctx.type = 'application/json';
ctx.body = { msg: 'other mock' };
});
app.listen(3000);
启动后访问其他路径会得到JSON,而/mock/img暂时无内容。这个分层方式让系统容易扩展,比如以后要加鉴权Mock,只需再写一个app.use插在最前。注意Koa默认不会帮我们设Content-Type为图片,必须手动在图片分支里指定ctx.type,否则浏览器会把二进制当附件或乱码文本。
用SVG字符串生成可控占位图
最省事且不需要任何图片处理库的办法,是直接构造SVG文本并返回。SVG本质是XML文本,Node.js里拼一个字符串就能画矩形、写文字、控颜色。我们解析ctx.query里的w、h、c参数,分别指代宽、高、颜色,然后套进模板。因为返回的是文本,不占内存文件,也不会有编码问题,Koa发ctx.body = svgString时把ctx.type设成image/svg+xml即可。
这种方案的优点是参数极度灵活,前端要红底白字还是透明灰块,改URL就行。下面示例根据查询参数生成带尺寸标注的色块,前端拿去当占位图能直接看到宽高,方便排查样式问题。SVG里用viewBox保证缩放清晰,文字用<text>居中。注意代码块里演示的标签名已按规则转义,实际返回给浏览器的字符串里必须是正常尖括号。
app.use(async (ctx, next) => {
if (ctx.path.startsWith('/mock/img')) {
const w = parseInt(ctx.query.w) || 200;
const h = parseInt(ctx.query.h) || 100;
const c = ctx.query.c || '#cccccc';
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${w}" height="${h}" viewBox="0 0 ${w} ${h}">` +
`<rect width="100%" height="100%" fill="${c}"/>` +
`<text x="50%" y="50%" fill="#333" font-size="16" text-anchor="middle" dominant-baseline="middle">${w}x${h}</text>` +
`</svg>`;
ctx.type = 'image/svg+xml';
ctx.body = svg;
return;
}
await next();
});
SVG的弱点是老版本IE和部分内嵌WebView对SVG当img src支持不全,若你的前端要覆盖极旧环境,就得换PNG。但对现代浏览器和大部分移动端,SVG占位图体积小、易读、好调试,是Mock阶段首选。我们还可以把颜色参数做成随机,模拟不同用户头像,只要在前端URL后拼?c=%23ff0000就能看到红色块。
用Buffer合成PNG以满足旧客户端
如果必须返回位图,不必引重型库,Node.js的zlib加手工拼PNG结构就能做纯色图,但过程繁琐。更实际的是用pngjs这类纯JS库,在内存画像素后输出Buffer。我们在Koa里ctx.body = buffer且ctx.type = 'image/png',浏览器照常渲染。下面示例用pngjs画一个指定颜色的方块,不写文件直接发内存数据。
这种方式保证了所有能显示PNG的地方都能用Mock图,包括某些只允许PNG的富文本编辑器封面。缺点是相比SVG,它占CPU算像素,高并发Mock时略吃力,但联调阶段流量极小无所谓。下面代码展示如何接收参数并返回PNG Buffer:
const { PNG } = require('pngjs');
app.use(async (ctx, next) => {
if (ctx.path.startsWith('/mock/png')) {
const w = parseInt(ctx.query.w) || 100;
const h = parseInt(ctx.query.h) || 100;
const png = new PNG({ width: w, height: h });
const color = ctx.query.c || '200,200,200';
const [r, g, b] = color.split(',').map(Number);
for (let i = 0; i < w * h; i++) {
const idx = i * 4;
png.data[idx] = r;
png.data[idx + 1] = g;
png.data[idx + 2] = b;
png.data[idx + 3] = 255;
}
const buf = PNG.sync.write(png);
ctx.type = 'image/png';
ctx.body = buf;
return;
}
await next();
});
把两种方案都挂到Koa上,前端按环境切/mock/img或/mock/png,Mock层就完整覆盖图片响应。总结来看,Koa的轻量设计让我们用几十行代码补齐了联调盲区,不用启Nginx放静态图,也不用改前端逻辑。后续若想模拟图片加载失败,只需在中间件里随机ctx.status = 500,前端错误回调立刻能被测到。
Node.jsKoamock_image修改时间:2026-08-14 12:06:34