'Display Pdf in browser using express js
I'm trying to serve a PDF via Express in a way it is displayed in browser:
app.post('/asset', function(request, response){
var tempFile="/home/applmgr/Desktop/123456.pdf";
fs.readFile(tempFile, function (err,data){
response.contentType("application/pdf");
response.send(data);
});
});
However, the browser shows binary content. How to handle this correctly?
Solution 1:[1]
Specifying how a file download is handled all comes down to the Content-disposition header. You can also specify the name of the file here as well. We also set the Content-type to ensure the browser knows what to do with the file given to it.
Express.js Example:
app.post('/url/to/hit', function(req, res, next) {
var stream = fs.readStream('/location/of/pdf');
var filename = "WhateverFilenameYouWant.pdf";
// Be careful of special characters
filename = encodeURIComponent(filename);
// Ideally this should strip them
res.setHeader('Content-disposition', 'inline; filename="' + filename + '"');
res.setHeader('Content-type', 'application/pdf');
stream.pipe(res);
});
Now if you look more closely at the Content-disposition, you'll notice the inline; field is what sets how the browser reacts to the file. If you want to force downloads, you can do so by setting inline; to attachment;
I've also found out (by being burnt a couple times), that if you set special characters in your filename, it can break. So I encodeURIComponent() the filename to ensure that doesn't happen.
Hope that helps others trying to figure out the same!
Edit
In the time between me posting this originally and now, I've found out how to correctly encode the content-disposition's filename parameter. According to the spec, the filename should be RFC5987 encoded. I ended up finding an example code snippet from MDN that correctly handles the encoding here (encodeURIComponent() isn't the entirely correct format for this field).
MDN Snippet
var fileName = 'my file(2).txt';
var header = "Content-Disposition: attachment; filename*=UTF-8''"
+ encodeRFC5987ValueChars(fileName);
console.log(header);
// logs "Content-Disposition: attachment; filename*=UTF-8''my%20file%282%29.txt"
function encodeRFC5987ValueChars (str) {
return encodeURIComponent(str).
// Note that although RFC3986 reserves "!", RFC5987 does not,
// so we do not need to escape it
replace(/['()]/g, escape). // i.e., %27 %28 %29
replace(/\*/g, '%2A').
// The following are not required for percent-encoding per RFC5987,
// so we can allow for a little better readability over the wire: |`^
replace(/%(?:7C|60|5E)/g, unescape);
}
Another note on top of this one, browsers don't fully comply with the spec either. Some characters will still come back incorrectly from a download (at least when I tested it).
You can get around this problem by updating how your downloads work. If your download URL ends with the filename (and you don't supply a filename attribute in the header), it will correctly get the filename from the URL encoded value. IE 'http://subdomain.domain-url.com/some/path/to/downloads/' + encodeURIComponent("You're there, download this!.pdf")
Jeeze, and all to supply a file name to your downloads!
Solution 2:[2]
My Solution for sending a PDF directly to the Browser:
app.get('/my/pdf', function (req, res) {
var doc = new Pdf();
doc.text("Hello World", 50, 50);
doc.output( function(pdf) {
res.type('application/pdf');
res.end(pdf, 'binary');
});
});
res.end() with the second param 'binary' did the trick in my case. Otherwise express interpret it as a string
Solution 3:[3]
Actually Express already has this feature for sending files. All you need is :
app.get('/sendMePDF', function(req, res) {
res.sendFile(__dirname + "/static/pdf/Rabbi.pdf");
})
Here the server will send the file "Rabbi.pdf" and it will open in browser like you open pdf in browser. I placed the file in "static" folder but you can place it anywhere, knowing that sendFile() takes as argument the absolute path (not relative one).
Solution 4:[4]
It is as simple as following code:
var express = require('express'),
fs = require('fs'),
app = express();
app.get('/', function (req, res) {
var filePath = "/files/my_pdf_file.pdf";
fs.readFile(__dirname + filePath , function (err,data){
res.contentType("application/pdf");
res.send(data);
});
});
app.listen(3000, function(){
console.log('Listening on 3000');
});
For complete repo:
Clone node-cheat pdf_browser, run node app followed by npm install express.
Happy Helping!
Solution 5:[5]
According to Express js documentation you can set the Content Type and the Content Disposition all in one function as shown below
fs.readFile(filePath, (err, data) => {
res.set({
"Content-Type": "application/pdf", //here you set the content type to pdf
"Content-Disposition": "inline; filename=" + fileName, //if you change from inline to attachment if forces the file to download but inline displays the file on the browser
});
res.send(data); // here we send the pdf file to the browser
});
Solution 6:[6]
post('/fileToSend/', async (req, res) => {
const documentPath = path.join(
__dirname,
'../assets/documents/document.pdf'
);
res.setHeader('Content-Type', 'application/pdf');
res.setHeader('Content-Disposition', 'attachment; filename=document.pdf');
return res.download(documentPath);
});
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Community |
| Solution 2 | st0ne |
| Solution 3 | Christiaan Westerbeek |
| Solution 4 | Zeeshan Hassan Memon |
| Solution 5 | Chinelo |
| Solution 6 | Leon Matota |
