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

Node.js API实现PDF下载重命名并返回的问题求助

Node.js后端PDF转发问题解答

问题背景

我是Node.js新手,需求是:后端收到POST请求时,从外部URL下载PDF文档,重命名后返回给客户端,文件无需保存到服务器。现有代码运行时出现“文件不存在”错误,且无法访问前端,想知道能不能用Postman测试API,以及当前实现的问题。

现有控制器代码

try {
      const get_request: any = req.body;
      const result = await printLabels(get_request,res);
      res.contentType("application/pdf");
      res.status(200).send(result);
    } catch (error) {
      const ret_data: errorResponse = await respondError(
        error,"Something Went Wrong.",
      );
      res.status(200).json(ret_data);
    }

printLabels函数代码

export const printLabels = async (request: any,response:any) => {
  try {
    const item_id = request.item_id;
    let doc=await fs.createReadStream(`some url with ${item_id}`);
    doc.pipe(fs.createWriteStream("Invoice_" + item_id + "_Labels.pdf"));
    return doc;
  } catch (error) {
    throw error;
  }
};

问题分析与解决方案

当前实现的核心问题

  • fs.createReadStream不支持读取URL:这个API是用来读取本地文件系统的文件,你传入外部URL会被当作本地路径处理,自然找不到文件,触发“文件不存在”错误。
  • 违反“不保存到服务器”的需求:代码里用doc.pipe(fs.createWriteStream(...))把PDF写入了服务器本地,完全没必要。
  • 流的返回方式错误:直接返回ReadStream再用res.send(result)无法正确将流传递给客户端,需要直接把流pipe到response对象上。

修正后的实现方案

我们需要用HTTP请求工具获取外部PDF的流,然后直接将流转发给客户端,同时设置响应头指定文件名。

方案1:用Node.js内置https模块(适配HTTPS外部链接)

import * as https from 'https';
import { IncomingMessage } from 'http';

export const printLabels = async (request: any, response: any): Promise<void> => {
  const item_id = request.item_id;
  const externalUrl = `你的真实外部PDF链接${item_id}`; // 替换为实际的PDF URL

  https.get(externalUrl, (res: IncomingMessage) => {
    // 设置响应头,指定PDF类型和下载文件名
    response.setHeader('Content-Type', 'application/pdf');
    response.setHeader('Content-Disposition', `attachment; filename="Invoice_${item_id}_Labels.pdf"`);
    
    // 直接将外部响应流转发给客户端
    res.pipe(response);

    // 处理流异常
    res.on('error', (err) => {
      throw err;
    });
  }).on('error', (err) => {
    throw err;
  });
};

对应的控制器代码调整:

try {
  const get_request: any = req.body;
  await printLabels(get_request, res);
} catch (error) {
  const ret_data: errorResponse = await respondError(
    error, "Something Went Wrong."
  );
  res.status(500).json(ret_data); // 建议用500状态码标识服务器错误,而非200
}

方案2:用axios库(更简洁,支持HTTP/HTTPS)

先安装依赖:npm install axios

import axios from 'axios';

export const printLabels = async (request: any, response: any): Promise<void> => {
  const item_id = request.item_id;
  const externalUrl = `你的真实外部PDF链接${item_id}`;

  const pdfStream = await axios.get(externalUrl, { responseType: 'stream' });
  
  response.setHeader('Content-Type', 'application/pdf');
  response.setHeader('Content-Disposition', `attachment; filename="Invoice_${item_id}_Labels.pdf"`);
  
  pdfStream.data.pipe(response);
};

控制器代码和方案1的调整一致即可。

Postman测试方法

完全可以用Postman测试,步骤如下:

  1. 新建POST请求,填入你的API接口地址(比如http://localhost:3000/你的接口路径)。
  2. 切换到Body标签,选择raw,格式选JSON,输入请求体示例:
    { "item_id": "123" }
    
  3. 点击Send,正常情况下Postman会自动下载返回的PDF,你可以在响应头中看到Content-Disposition配置,也能在Body区域预览PDF内容。

内容的提问来源于stack exchange,提问作者Aman Sharma

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 04:25:37