快速.JS:通过跨源URL强制下载PDF文件



编辑:

标题已更改,以便任何人都可以建议使用类似技术和平台实现相同结果的替代解决方案。没有必要必须res.attachment.

我试图通过跨源URL强制下载PDF文件。代码似乎按预期工作,但下载的文件为零字节,为什么?

在服务器上:

app.get("/download", (req, res) => {
res.type("application/octet-stream");
// Note that the PDF URL is Cross-Origin.
res.attachment("https://cross-origin-domain-name.com/downloads/fiename.pdf");
res.send();
});

在 HTML 上:

<a class="a-very-big-button" href="/download">Download PDF</a>

我错过了什么吗?我确实尝试了许多其他选项,如res.download()readStream.pipe(res)方法,但其中大多数要求文件位于同一台服务器上。对于我的应用程序,我需要帮助我的客户根据他们提交的 URL 提供下载 PDF 按钮,该 URL可能位于他们的 Web 服务器上。任何建议将不胜感激!谢谢。

res.attachment确实将字符串作为其唯一的参数,但该字符串用作浏览器的提示,如果用户决定保存文件,文件名应该是什么。它不允许您指定要获取的 URL 或文件名。

因为您没有发送任何数据(res.send()没有缓冲区或.write()调用),所以只是关于文件名应该是什么的建议,下载是 0 字节。

您可以做的是通过管道将HTTP请求传送到res,这将使您的服务器下载并转发文件。该文件不会缓存在您的服务器上,并且会"花费"上传和下载容量(但没有存储)。


有关如何通过管道将 HTTPS 请求传送到响应的示例。

代替 Node 的内置https.request您可以使用许多其他库。它们中的大多数都支持流文件。这些库可以更轻松地处理错误。

const express = require('express');
const https = require('https');
const app = express();
const url = 'https://full-url-to-your/remote-file.pdf';
const headerAllowList = [
'content-type', 'content-length', 'last-modified', 'etag'
];
app.use('/', async (req, res, next) => {
// Create a HTTPS request
const externalRequest = https.request(url, {
headers: {
// You can add headers like authorization or user agent strings here.
// Accept: '*/*',
// 'User-Agent': '',
},
}, (externalResponse) => {
// This callback won't start until `.end()` is called.
// To make life easier on ourselves, we can copy some of the headers
// that the server sent your Node app and pass them along to the user.
headerAllowList
.filter(header => header in externalResponse.headers)
.forEach(header => res.set(header, externalResponse.headers[header]));
// If we didn't have content-type in the above headerAllowList, 
// you could manually tell browser to expect a PDF file.
// res.set('Content-Type', 'application/pdf');
// Suggest a filename
res.attachment('some-file.pdf');
// Start piping the ReadableStream to Express' res.
externalResponse.pipe(res);
});
externalRequest.on('error', (err) => {
next(err);
});
// Start executing the HTTPS request
externalRequest.end();
});
app.listen(8000);

如果您访问localhost:8000,您将获得一个带有保存文件对话框的 PDF,其中包含建议的文件名,从指定的 URL 提供。

最新更新