Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

res.sendfile in Node Express with passing data along

Is there any way to redirect to an HTML file from a Node.JS application with something like: res.sendFile of express and pass a JSON data along to the html file?

like image 258
user3393991 Avatar asked Oct 08 '15 22:10

user3393991


People also ask

What does res sendFile do?

The res. sendFile() function basically transfers the file at the given path and it sets the Content-Type response HTTP header field based on the filename extension.

How do I send a sendFile?

The sendFile() Method. The Express framework provides a sendFile() method available on the response object which can be used to send static files to the client. Next, create an app. js file in the root folder of your project and add the following code to create a simple Express.

Is Res sendFile async?

res. sendFile() is asynchronous and it will end its own response if it is successful. So, when you call res.

What is Post () in Express?

js POST Method. Post method facilitates you to send large amount of data because data is send in the body. Post method is secure because data is not visible in URL bar but it is not used as popularly as GET method. On the other hand GET method is more efficient and used more than POST.


Video Answer


2 Answers

I know this is late but I wanted to offer a solution which no one else has provided. This solution allows a file to be streamed to the response while still allowing you to modify the contents without needing a templating engine or buffering the entire file into memory.

Skip to the bottom if you don't care about "why"

Let me first describe why res.sendFile is so desirable for those who don't know. Since Node is single threaded, it works by performing lots and lots of very small tasks in succession - this includes reading from the file system and replying to an http request. At no point in time does Node just stop what it's doing and read an entire from the file system. It will read a little, do something else, read a little more, do something else. The same goes for replying to an http request and most other operations in Node (unless you explicitly use the sync version of an operation - such as readFileSync - don't do that if you can help it, seriously, don't - it's selfish).

Consider a scenario where 10 users make a request for for the same file. The inefficient thing to do would be to load the entire file into memory and then send the file using res.send(). Even though it's the same file, the file would be loaded into memory 10 separate times before being sent to the browser. The garbage collector would then need to clean up this mess after each request. The code would be innocently written like this:

app.use('/index.html', (req, res) => {    fs.readFile('../public/index.html', (err, data) => {       res.send(data.toString());    }); }); 

That seems right, and it works, but it's terribly inefficient. Since we know that Node does things in small chunks, the best thing to do would be to send the small chunks of data to the browser as they are being read from the file system. The chunks are never stored in memory and your server can now handle orders of magnitude more traffic. This concept is called streaming, and it's what res.sendFile does - it streams the file directly to the user from the file system and keeps the memory free for more important things. Here's how it looks if you were to do it manually:

app.use('/index.html', (req, res) => {     fs.createReadStream('../public/index.html')     .pipe(res); }); 

Solution

If you would like to continue streaming a file to the user while making slight modifications to it, then this solution is for you. Please note, this is not a replacement for a templating engine but should rather be used to make small changes to a file as it is being streamed. The code below will append a small script tag with data to the body of an HTML page. It also shows how to prepend or append content to an http response stream:

NOTE: as mentioned in the comments, the original solution could have an edge case where this would fail. For fix this, I have added the new-line package to ensure data chunks are emitted at new lines.

const Transform = require('stream').Transform; const parser = new Transform(); const newLineStream = require('new-line');  parser._transform = function(data, encoding, done) {   const str = data.toString().replace('</body>', '<script>var data = {"foo": "bar"};</script></body>');   this.push(str);   done(); };  // app creation code removed for brevity  app.use('/index.html', (req, res) => {     res.write('<!-- Begin stream -->\n');     fs     .createReadStream('../public/index.html')     .pipe(newLineStream())     .pipe(parser)     .on('end', () => {         res.write('\n<!-- End stream -->')     }).pipe(res); }); 
like image 78
Ryan Wheale Avatar answered Sep 30 '22 13:09

Ryan Wheale


You get one response from a given request. You can either combine multiple things into one response or require the client to make separate requests to get separate things.

If what you're trying to do is to take an HTML file and modify it by inserting some JSON into it, then you can't use just res.sendFile() because that just reads a file from disk or cache and directly streams it as the response, offering no opportunity to modify it.

The more common way of doing this is to use a template system that lets you insert things into an HTML file (usually replacing special tags with your own data). There are literally hundreds of template systems and many that support node.js. Common choices for node.js are Jade (Pug), Handlebars, Ember, Dust, EJS, Mustache.

Or, if you really wanted to do so, you could read the HTML file into memory, use some sort of .replace() operation on it to insert your own data and then res.send() the resulting changed file.

like image 35
jfriend00 Avatar answered Sep 30 '22 12:09

jfriend00