res.attachment
does take a string as its only argument, but that string is used as a hint to the browser what the filename should be if the user decides to save the file. It does not allow you to specify a URL or filename to fetch.
Because you're not sending any data (res.send()
without a Buffer or .write()
calls), just a suggestion as to what the filename should be, the download is 0 bytes.
What you could do is pipe a HTTP request to res
, which will have your server download and forward the file. The file will not be cached on your server and will 'cost' both upload and download capacity (but no storage).
An example on how to pipe a HTTPS request to a response.
Instead of Node's built-in https.request
you could use many other libraries. Most of them support streaming files. These libraries can make it easier to handle errors.
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);
If you visit localhost:8000
you'll be served a PDF with a save-file dialog with the suggested filename, served from the specified URL.