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测试,步骤如下:
- 新建POST请求,填入你的API接口地址(比如
http://localhost:3000/你的接口路径)。 - 切换到Body标签,选择
raw,格式选JSON,输入请求体示例:{ "item_id": "123" } - 点击Send,正常情况下Postman会自动下载返回的PDF,你可以在响应头中看到
Content-Disposition配置,也能在Body区域预览PDF内容。
内容的提问来源于stack exchange,提问作者Aman Sharma
相关产品推荐
相关产品推荐

