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

如何通过GraphQL查询调用pdfmake实现PDF文件下载?

解决方案

你说得对,pdfmake的download()方法是前端浏览器环境专用的,后端(Node.js)没法直接调用它触发下载。后端要实现调用查询时触发下载,核心思路是生成PDF的二进制数据,然后通过响应头告诉浏览器这是一个需要下载的PDF文件,而非将文件存到服务器本地。

以下是修改后的Resolver代码,以Apollo Server(Express集成)为例:

import { Resolver, Query, Authorized, Ctx } from "type-graphql";
import Pdfmake from "pdfmake";
import { Readable } from "stream";

@Resolver()
export class PdfResolver {
  @Authorized()
  @Query(() => String, { nullable: true }) // 可自定义标量类型,或直接处理响应
  async CreatePdf(@Ctx() ctx: any) {
    const fonts = {
      Roboto: {
        normal: "fonts/roboto/Roboto-Regular.ttf",
        bold: "fonts/roboto/Roboto-Medium.ttf",
        italics: "fonts/roboto/Roboto-Italic.ttf",
        bolditalics: "fonts/roboto/Roboto-MediumItalic.ttf",
      },
    };

    const pdfmake = new Pdfmake(fonts);
    const docDefinition = {
      content: ["Hello World!"],
    };

    const pdfDoc = pdfmake.createPdfKitDocument(docDefinition);
    
    // 收集PDF二进制数据到Buffer
    let chunks: Uint8Array[] = [];
    pdfDoc.on("data", (chunk: Uint8Array) => chunks.push(chunk));
    
    pdfDoc.end();

    return new Promise((resolve) => {
      pdfDoc.on("end", () => {
        const pdfBuffer = Buffer.concat(chunks);
        
        // 设置响应头触发浏览器下载
        ctx.res.setHeader("Content-Type", "application/pdf");
        ctx.res.setHeader("Content-Disposition", 'attachment; filename="test.pdf"');
        
        // 将Buffer写入响应流
        const stream = new Readable();
        stream.push(pdfBuffer);
        stream.push(null);
        stream.pipe(ctx.res);
        
        resolve(null); // 已通过响应流返回数据,Resolver无需返回字符串
      });
    });
  }
}

关键改动说明:

  • 移除fs.writeStream,改为监听PDF文档的data事件收集二进制数据,最终合并为Buffer。
  • 通过GraphQL的@Ctx()获取Express响应对象(ctx.res),设置两个核心响应头:
    • Content-Type: application/pdf:告知浏览器返回内容为PDF格式。
    • Content-Disposition: attachment; filename="test.pdf":告知浏览器以附件形式下载文件,并指定文件名。
  • 将PDF Buffer通过可读流写入响应,浏览器收到后会自动触发下载流程。

注意事项:

  1. 确保字体文件路径在后端环境中可访问,建议使用绝对路径避免路径问题。
  2. 若你的GraphQL服务器并非基于Express,需调整获取响应对象的方式(适配对应集成框架的API)。
  3. Resolver的返回类型可按需调整,比如自定义PDF标量类型,或直接返回null(因已通过响应流返回数据)。

内容的提问来源于stack exchange,提问作者Jorge H

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 14:41:25