如何在NestJS服务端用JSON/对象数据生成PDF并上传至S3?
解决方案
依赖安装
先安装所需的npm包:
npm install pdfkit @aws-sdk/client-s3 @aws-sdk/lib-storage # 若使用NestJS官方AWS模块,可额外安装 npm install @nestjs/aws-sdk
1. 配置S3客户端
在NestJS模块中配置S3客户端(以@nestjs/aws-sdk为例):
// src/s3/s3.module.ts import { Module } from '@nestjs/common'; import { AwsModule } from '@nestjs/aws-sdk'; import { S3Client } from '@aws-sdk/client-s3'; @Module({ imports: [ AwsModule.forRoot({ client: { service: S3Client, region: '你的S3区域', credentials: { accessKeyId: '你的AWS Access Key', secretAccessKey: '你的AWS Secret Key', }, }, }), ], exports: [AwsModule], }) export class S3Module {}
2. 实现PDF生成与上传服务
创建服务类,直接从finalReport对象生成PDF并上传至S3:
// src/pdf/pdf.service.ts import { Injectable } from '@nestjs/common'; import { S3 } from '@aws-sdk/client-s3'; import { Upload } from '@aws-sdk/lib-storage'; import * as PDFDocument from 'pdfkit'; import { Buffer } from 'buffer'; @Injectable() export class PdfService { constructor(private readonly s3: S3) {} async generateAndUploadReport(finalReport: any): Promise<string> { // 初始化PDF文档 const doc = new PDFDocument({ margin: 50 }); const buffers: Buffer[] = []; // 收集PDF输出的二进制数据 doc.on('data', (chunk) => buffers.push(chunk)); doc.on('end', () => {}); // 构建PDF内容 // 添加标题 doc.fontSize(20).text('任务完成报告', { align: 'center' }); doc.moveDown(2); // 添加基础信息 doc.fontSize(14); doc.text(`任务ID: ${finalReport.taskId}`); doc.moveDown(0.5); doc.text(`报告内容: ${finalReport.report}`); doc.moveDown(0.5); doc.text(`客户姓名: ${finalReport.nameCustomer}`); doc.moveDown(0.5); doc.text(`客户备注: ${finalReport.notesCustomer}`); doc.moveDown(0.5); doc.text(`完成时间: ${new Date(finalReport.createdAt).toLocaleString()}`); doc.moveDown(0.5); doc.text(`维修人员: ${finalReport.user.name} (${finalReport.user.email})`); doc.moveDown(2); // 添加维修人员签名 doc.fontSize(12).text('维修人员签名:'); doc.moveDown(0.5); const handymanSigBuffer = this.base64ToBuffer(finalReport.signatureHandyman); doc.image(handymanSigBuffer, { width: 200, height: 100 }); doc.moveDown(2); // 添加客户签名 doc.fontSize(12).text('客户签名:'); doc.moveDown(0.5); const customerSigBuffer = this.base64ToBuffer(finalReport.signatureCustomer); doc.image(customerSigBuffer, { width: 200, height: 100 }); // 结束PDF文档 doc.end(); // 合并为完整的PDF Buffer const pdfBuffer = Buffer.concat(buffers); // 上传至S3 const uploadParams = { Bucket: '你的S3存储桶名称', Key: `reports/${finalReport.taskId}_${Date.now()}.pdf`, Body: pdfBuffer, ContentType: 'application/pdf', }; const upload = new Upload({ client: this.s3, params: uploadParams, }); await upload.done(); // 返回S3文件访问地址(若存储桶私有,可生成预签名URL) return `https://${uploadParams.Bucket}.s3.${process.env.AWS_REGION}.amazonaws.com/${uploadParams.Key}`; } // 工具方法:Base64图片转Buffer private base64ToBuffer(base64Str: string): Buffer { const pureBase64 = base64Str.replace(/^data:image\/png;base64,/, ''); return Buffer.from(pureBase64, 'base64'); } }
3. 控制器调用服务
创建控制器暴露接口,触发PDF生成与上传:
// src/report/report.controller.ts import { Controller, Post, Body } from '@nestjs/common'; import { PdfService } from '../pdf/pdf.service'; @Controller('reports') export class ReportController { constructor(private readonly pdfService: PdfService) {} @Post('generate') async generateReport(@Body() body: { finalReport: any }) { const s3Url = await this.pdfService.generateAndUploadReport(body.finalReport); return { success: true, s3Url }; } }
关键说明
- pdfkit:无需转HTML,直接通过代码API构建PDF内容,灵活控制文本、图片的布局与样式,适配简单结构的需求。
- S3上传:使用
@aws-sdk/lib-storage的Upload类支持分段上传,小文件也能稳定处理。 - Base64图片处理:移除前缀后转成Buffer,直接传入pdfkit的
image方法即可插入到PDF中。
内容的提问来源于stack exchange,提问作者Adarsh Singh
相关产品推荐
相关产品推荐

