在Nest框架的开发过程中,我们经常使用Mock数据来模拟接口返回,以便前端并行开发。但有些场景下,比如生成报表预览、自动化视觉测试或给非技术人员展示数据,单纯返回JSON并不直观。NestMock2Image就是一个基于Node.js的思路,它把Nest里的Mock数据在服务端转换成图片文件,既能脱离浏览器渲染,也能批量产出。下面我们从一个基础的Nest Mock服务说起,逐步构建这个转换工具。

搭建支持Mock数据的Nest服务
要实现NestMock2Image,第一步是有一个能稳定输出Mock数据的Nest接口。Nest本身推荐使用拦截器或者自定义的Provider来注入Mock逻辑。我们可以创建一个MockService,在开发环境下返回固定的结构化数据,例如用户列表或销售记录。这样做的好处是,后续图片生成模块可以直接调用同一个服务方法,而不必关心数据来源是真实数据库还是Mock。
具体实现时,我们新建一个getReportData方法,返回一个包含标题、表头和行数据的对象。为了演示,这里用硬编码对象模拟。注意在Nest中,控制器只需调用该服务并把结果通过@Get路由暴露即可。如果使用了class-transformer之类的库,也要确保序列化后字段名称与图片绘制时所用的key一致,否则会出现取不到值的尴尬。
import { Injectable } from '@nestjs/common';
@Injectable()
export class MockService {
getReportData() {
return {
title: '月度销售报表',
headers: ['姓名', '部门', '销售额'],
rows: [
['张三', '华东', 12000],
['李四', '华北', 9800],
['王五', '华南', 15300],
],
};
}
}
使用Node.js canvas库绘制图片
拿到Mock数据后,下一步是在Node.js里把它画出来。社区里最成熟的方案是canvas这个npm包,它基于Cairo图形库,提供了和浏览器Canvas几乎一致的API。我们在Nest项目里安装canvas后,可以写一个独立的renderToImage函数,接收数据对象,创建createCanvas实例,然后用fillText和strokeRect画出标题与表格。
绘制表格时要先计算每行高度和列宽。例如设定字体为16px,行高30px,画布宽度根据列数动态扩展。一个常见误区是直接用默认字体,导致中文变成方块,这是因为系统缺少对应字体文件。我们需要在registerFont中显式加载一个ttf中文字体,比如微软雅黑或思源黑体,并给ctx.font赋值如16px MicrosoftYaHei。下面代码展示了基础绘制流程,包含标题和简单三列排版。
const { createCanvas, registerFont } = require('canvas');
registerFont('C:\fonts\msyh.ttf', { family: 'MicrosoftYaHei' });
function renderToImage(data) {
const colWidth = 200;
const rowHeight = 30;
const width = colWidth * data.headers.length;
const height = rowHeight * (data.rows.length + 2);
const canvas = createCanvas(width, height);
const ctx = canvas.getContext('2d');
ctx.font = '20px MicrosoftYaHei';
ctx.fillText(data.title, 10, 25);
ctx.font = '16px MicrosoftYaHei';
data.headers.forEach((h, i) => {
ctx.fillText(h, i * colWidth + 10, 55);
});
data.rows.forEach((row, r) => {
row.forEach((cell, c) => {
ctx.fillText(String(cell), c * colWidth + 10, 55 + (r + 1) * rowHeight);
});
});
return canvas.toBuffer('image/png');
}
上面的函数返回的是PNGBuffer,可以直接写文件,也可以通过Nest的Res对象以流的形式返回给客户端。如果希望图片更清晰,可以把画布尺寸放大两倍,然后用ctx.scale(2, 2)绘制,最后导出时再缩回显示尺寸,这样文字边缘更平滑。此外,若数据量很大,建议分页绘制,避免单张图过长导致内存占用过高。
在Nest中集成并暴露图片接口
最后一步是把渲染逻辑挂到Nest路由上。我们可以新建一个MockController,注入前面的MockService,并新增一个@Get('image')接口。在接口处理函数中,先取数据,再调用renderToImage,然后设置响应头为image/png,用res.end(buffer)输出。这样就完成了从Mock数据到图片的闭环,前端只需访问该接口就能拿到图。
为了工程化,最好把渲染函数抽到ImageRendererModule里,并区分开发和生产环境。生产环境可关闭Mock,直接接真实服务;开发环境则默认走Mock。同时要注意,Node.js的canvas包在安装时可能需要系统依赖,如Linux下要装libcairo2-dev,否则npm install会失败。下面示例展示控制器如何返回图片,并简单处理异常。
import { Controller, Get, Res } from '@nestjs/common';
import { Response } from 'express';
import { MockService } from './mock.service';
import { renderToImage } from './image.util';
@Controller('mock')
export class MockController {
constructor(private readonly mockService: MockService) {}
@Get('image')
getImage(@Res() res: Response) {
try {
const data = this.mockService.getReportData();
const buffer = renderToImage(data);
res.setHeader('Content-Type', 'image/png');
res.end(buffer);
} catch (e) {
res.status(500).send('render failed');
}
}
}
通过上述三层结构,我们既保留了Nest原有的Mock能力,又扩展了图片生成。后续还能加入水印、主题色、图表等更复杂的绘制。只要把握住数据同源、字体注册、清晰度和异常兜底这几个点,NestMock2Image就能稳定跑在Node.js环境里,为团队节省大量手动截图和对齐的时间。
Node.jsNestMock2Imagecanvas修改时间:2026-08-17 20:20:35