I've got a big system where I need to generate a PDF file. I'd like to access it via REST API and, of course, store the file locally.
The file content depends on many parameters what the content of this file should be, i.e. time: from-to, filters, sorting and many, many more parameters; they form a JSON object which perfectly fits into POST parameters. The parameters cannot go through GET, since they're too big.
There is the FileSaver library that works perfectly fine on modern browsers. I created an online demo. But when I downloaded old browsers - firefox11, firefox12, firefox15, it didn't work at all, even though I included the Blob.js polyfill - it opened a new tab with URL like: blob:457-343457-34574567-4576456 that was unable to be saved. I need to support many browsers, not only the new ones.
The question is - I've got JSON parameters object inside my SPA app - how should I design this PDF binary file download?
I was thinking of 3 approaches:
force browser to create a file on localhost - using FileSaver. WOrks fine for modern browsers, doesn't work for old ones
create downloadable link. I shoot a POST to the REST API, incuding all parameters, the REST API returns something like: {"download": "mysite.com/download/ms2h5d34h53m"}, the response is used to display a link to the user; the user might click the link (with no AJAX) and the server-side API should just return a file like in the old times.
not mine, but somewhere I read I could create an invisible form that shoots a POST to the server, which triggers file download (perhaps this would reduce the step with returning the {"download": "mysite.com/download/ms2h5d34h53m"} JSON)
I need a guidance on how to do that right.
I tried to create a test express.js server below. When I access http://localhost:8081/download directly, I see a PDF file downloaded locally. But when I try to access it via ajax/js:
then the content is fetched as binary stream:
var fs = require('fs');
var express = require('express');
var app = express();
app.get('/', function (req, res) {
res.send('Hello World');
});
app.get('/download', function(req, res){
var file = fs.readFileSync(__dirname + '/example.pdf', 'binary');
res.setHeader('Content-Type', 'application/pdf');
res.setHeader('Content-Length', file.length);
res.setHeader('Content-Disposition', 'attachment; filename=new-name.pdf');
res.setHeader('filename', 'sample.pdf');
res.write(file, 'binary');
res.end();
});
var server = app.listen(8081, function () {
var host = server.address().address;
var port = server.address().port;
console.log("Example app listening at http://%s:%s", host, port);
});
Related
so I am trying to build a website that allows users to download files that are located in the server computer when the users access the website and click a download button.
I wish to use as few libraries as possible due to some real world limitations. Ideally no Express or Ajax. And I think it should be fully possible with just vanilla node.js
From my search on the internet it seems most of the code is of this form:
const fs = require('fs');
const https = require('https');
// URL of the image
const url = 'GFG.jpeg';
https.get(url,(res) => {
// Image will be stored at this path
const path = `${__dirname}/files/img.jpeg`;
const filePath = fs.createWriteStream(path);
res.pipe(filePath);
filePath.on('finish',() => {
filePath.close();
console.log('Download Completed');
})
})
However, the code doesn't seem to be doing what I want.
First, it requires an url, so it is more about directing a resource online to another location. Whereas I want to actually serve a locally stored file on the server to users when they access the website.
Second, it appears to be downloading to the server computer. But what I want is to let users download to their own client devices. Basically the normal download function you would encounter when you want to download something on the Internet and you see your browser's "Download" section having some new entries.
How can I achieve what I want?
I'm a total noob at this, so it would be great if I can get a skeleton code with some dummy file or pathname.
Appreciate any guidance. Thanks!
You are missing an http.server. http.get just does a web request and as you said you don't want to do that.
Here is some example code creating a server and serving a single file without using express:
const fs = require('fs');
const path = require('path');
const http = require('http');
http.createServer(function(request, response) {
var filePath = path.join(__dirname, '/files/img.jpeg');
response.writeHead(200);
var readStream = fs.createReadStream(filePath);
readStream.pipe(response);
}).listen(2000);
I am new to js.
I am trying to display a pdf file in browser, however I am continuously getting the same respond 'Cannot GET..."
I've tried it different ways.
router.get("/en/tc", function(req, res){
// res.sendFile("/assets/downloads/TC_TS_eng.pdf", {root: "."});
res.download("./assets/downloads/TC_TS_eng.pdf");
})
As well as via 'fileSend'.
It all works well as long as I run it locally. However as soon as I move it to the server it starts returning the above mentioned response.
Any help will be highly appreciated.
You could do this:
app.get("/", function(req, res){
res.sendFile(__dirname + "/test.pdf");
});
What I did here is quite simple. I sent the file when the user goes to the root directory (/) and send the pdf file. __dirname is directory name, which basically makes sure that even when you host on, say heroku, you can still get the file beacuse it gets the full directory path to the file, and then + the pdf name. Hope this helps! Good luck.
I'm using express 4.x and have turned on compression middleware in my app.js like this:
var compression = require('compression');
var app = express();
app.use(compression());
app.use('/', require('./static'));
app.use('/api/xxx', require('./api/xxx'));
When I check in Safari web inspector, some files, like my app.js is indeed compressed, you can see a difference (though small) in file size:
but others like api requests are not:
There seems to be no difference in size, given that my server simply sends json on request, why the data transferred are not heavily compressed?
it is because you need to set the compression level.
Read the documentation here: https://github.com/expressjs/compression
Mine is set for max compression like so:
// Compress content
app.use(compression({
level: 9,
memLevel: 9
}));
I have created a Node.js server that worked well when the Javascript was part of the HTML page. I moved the JS to another file and added some images. Now it won't load the images or the JS into the browser. However, the web page renders perfectly when I open the web page directly. This is what my server looks like:
app.get('/',function(req,res){
res.end('Hello World!Go to /map to see the google map');
});
app.get('/map',function(req,res){
var conn;
//images must be sent to the client from the server...
res.sendfile(__dirname+'/client/google_maps.html');
//receiving requests from jQuery
});
I am not using the Express project structure or the Express middleware or Express configuration to do this.
If that's all your code, I think the problem you met is reasonable. You didn't tell your server how to respond your images and scripts when browser requested. For example in your google_map.html file you have <script src="myjs.js"></script>, then your browser will ask your node application to give the content of myjs.js but your server don't know how to deal with it.
You could try to add code like below to see if it helps.
app.get('/myjs.js', function (req, res) {
res.sendfile(__dirname + '/myjs.js');
});
As dimadima said, Express provides a module to handle static files that you can use like
app.use(express.static(__dirname + '/public'));
The following code is an exemple of code to serve static files in express on node.js. If I ask the server a .css file there is no problem, but if I ask an image such as a jpg or png, it loads a white page (no /GET error or anything, a simple white page). In my developer tool in my browser I see the following warning: 1Resource interpreted as Document but transferred with MIME type image/jpeg. How can I fix this?
I am using cloud9ide and express 2.4.6
var express = require("express"),
app = express.createServer();
app.use(express.static(__dirname + '/static'));
app.get('/', function(req, res){
res.send('Hello World');
});
app.listen(process.env.C9_PORT);
It looks like the file in question is not in JPEG format. Can you save that URL as a file using wget, curl or similar tools and open that file in a text editor?
A valid JPEG file should look like binary garbage and should have "JFIF" signature string close to the beginning (byte offset 6 I think).
it is possible that the file contains an error message instead of valid JPEG data.
It seems to be a bug from cloud9 ide. I tried my code locally and it worked. There is a ticket open on cloud9ide at: http://cloud9ide.lighthouseapp.com/projects/67519/tickets/390-get-png-image-not-working-in-preview-mode#ticket-390-4