You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 12:53:30