Routed page won't render if callback contains process.exit - node.js

I'm trying to render a page on a web browser and then exit the Node.js express webserver that served up the page. The code I'm using in the function that is called to do this is:
var express = require('express');
var router = express.Router();
router.get('/restart', function(req, res, next) {
res.render('resetTimer', {}, function() {
console.log("Render resetTimer page and exit.");
process.exit(); // kill Express webserver
});
});
However, I'm getting
This site can’t be reached
localhost refused to connect.
in the web browser, which suggests that the exit is happening before the web page is rendered, even though the exit command is in a callback. If I comment out the process.exit command I see the console log message, but if I don't comment it out, the page isn't rendered and the log message isn't output.
What am I missing?

The res.render() callback is called when the page has been handed off to the response stream, even though it may not yet have been fully delivered to the client. So, if you kill the process at that point, the client delivery may not complete.
I can think of two ways to work around this:
Create a listener for the close event on the response stream and when you get that event, you will know that everything has been sent and you can shut down your server. This will not allow for any other page resources that might need to be loaded (images, style sheets, fonts, etc...) since they may be requested after the page had loaded.
Put an ajax call in the page itself so that AFTER the page loads, it makes the ajax call and then you don't actually restart your server until you get the ajax call. If you don't make the Ajax call until the window load event, then you could also make sure that all other page resources were loaded before rebooting the server.
Note that either of these options allow all sorts of DOS attacks on your server (causing it to reboot whenever an attacker wants).

Related

running function after res.send

I'm trying to run this code
module.exports = async (req, res, next) => {
res.set('Content-Type', 'text/javascript');
const response = {};
res.status(200).render('/default.js', { response });
await fn(response);
};
fn is a function that calls an api to a service that will output to the client something. but its dependent on the default.js file to be loaded first. How can do something like
res.render('/default.js', { response }).then(async() => {
await fn(response);
};
tried it, but doesn't seem to like the then()
also, fn doesn't return data to the client, it calls an api service that is connected with the web sockets opened by the code from default.js that is rendered.
do i have to make an ajax request for the fn call and not call it internally?
any ideas?
Once you call res.render(), you can send no more data to the client, the http response has been sent and the http connection is done - you can't send any more to it. So, it does you no good to try to add something more to the response after you call res.render().
It sounds like you're trying to put some data INTO the script that you send to the browser. Your choices for that are to either:
Get the data you need to with let data = await fn() before you call res.render() and then pass that to res.render() so your template engine can put that data into the script file that you send the server (before you send it).
You will need to change the script file template to be able to do this so it has appropriate directives to insert data into the script file and you will have to be very careful to format the data as Javascript data structures.
Have a script in the page make an ajax call to get the desired data and then do your task in client-side Javascript after the page is already up and running.
It looks like it might be helpful for you to understand the exact sequence of things between browser and server.
Browser is displaying some web page.
User clicks on a link to a new web page.
Browser requests new web page from the server for a particular URL.
Server delivers HTML page for that URL.
Browser parses that HTML page and discovers some other resources required to render the page (script files, CSS files, images, fonts, etc...)
Browser requests each of those other resources from the server
Server gets a request for each separate resource and returns each one of them to the browser.
Browser incorporates those resources into the HTML page it previously downloaded and parsed.
Any client side scripts it retrieved for that page are then run.
So, the code you show appears to be a route for one of script files (in step 5 above). This is where it fits into the overall scheme of loading a page. Once you've returned the script file to the client with res.render(), it has been sent and that request is done. The browser isn't connected to your server anymore for that resource so you can't send anything else on that same request.

Why is res.render() not doing changing the front-end? [duplicate]

I have basic express js application with following route:
router.get('/', function(req, res){
res.render('login');
});
It works fine - after logging into main page on my localhost, html from login.pug is nicely rendered on client side. However when my app runs, sometimes I want to render another pug file, when there already is html rendered on client side:
app.get('/dashboard', function(req, res){
res.render('dashboard', {user: req.query.login});
});
But when get request is send on'dashboard'path, nothing happens. As I understand, this happens because res.render just parses pug file into HTML and sends it to client as plain string (which I can inspect in browser developers tool, when I check AJAX response I see exactly rendered HTML).
Now my question is: is there a way to render HTML from res.render in client automatically? So on server side I just write res.render('template') and on client side page is re-rendered without handling the response?
I know I can clear whole DOM and append received string into document.body, I know also that I can make a POST form request and then page will be re-rendered automatically, but I want to avoid both solutions (don't ask why).
Thank you for help in advance.
When your Javascript sends an Ajax request, the response from that Ajax request is just returned back to your Javascript. That's it. The browser does not show anything. If you want to do something with that response, then it is the responsibility of your Javascript to do something with it (insert it in the page to show it, etc...).
If what you really want is that you want the browser to actually go to the /dashboard URL and then show that page, then your Javascript can just do:
window.location = '/dashboard';
This will tell the browser to fetch the contents of that URL, it will make a request to your server, your server will return the rendered HTML and the browser will display it in the page and show /dashboard as the URL in the browser bar. That should do everything you want.
So, it's totally up to your Javascript. Pick the right tool for the job. Either fetch data for your Javascript with an Ajax call and process the result in your Javascript or instruct the browser to load a new page. One or the other.
But when get request is send on'dashboard'path, nothing happens. As I understand, this happens because res.render just parses pug file into HTML and sends it to client as plain string (which I can inspect in browser developers tool, when I check AJAX response I see exactly rendered HTML).
Yes, that what Ajax requests do. They fetch content from the server and return the data back to your Javascript (and only to your Javascript).
is there a way to render HTML from res.render in client automatically?
Yes, use window.location = '/dashboard'; from your Javascript.
So on server side I just write res.render('template') and on client side page is re-rendered without handling the response?
Not from an ajax call. Ajax calls never automatically display content. Never. Ajax calls are programmatic requests that return data to your script. That's what they are. But, yes from Javascript you can cause content to be automatically displayed by setting window.location to a new URL.

node.js - express - render multiple views

I'ld like to send two successive ejs page to the client using the following code:
app.post('/', function(req,res) {
res.render('yourDemandIsBeingProceed.ejs');
//some code which require time (open an external programm, run a script, edit a response)
res.render('hereIsYourResult.ejs');
res.end();
});
So, once once the client post his form, he receives a page asking him to wait for a few seconds and then the page containing the response is send.
any suggestion?
many thx
What you can do is have client-side code in yourDemandIsBeingProceed.ejs when the page loads that performs a get/post request to a different endpoint. When the result from that is received, hide/show different elements inside yourDemandIsBeingProceed.ejs so it looks more like hereIsYourResult.ejs
What you really should do is have the user submit information via front end AJAX and put up a loading graphic until the JSON response gets back. AJAX was developed for situations exactly like this.

Automatically accessing a route periodically in express.js

I am writing a node/express app that uses the request module get the json data from a url when a route is hit. Also I want to continuously get the data without hitting the reload button from the browser.Is there a way to automatically access the route periodically.
You can have Javascript in the browser that uses setInterval() to repeatedly call a function that makes an Ajax call to your server, fetches new data from your server and then inserts it into the page.
If you just want you page to reload automatically, you can use the meta refresh tag. Example:
<meta http-equiv="refresh" content="3;url=http://www.mozilla.org/">
Or, if your question is really about how to you just regular do some operation in node.js, then you can just use setInterval() within node.js to call some function every xxx ms.
// execute a function every 5 seconds
setInterval(function() {
// do something here
}, 5000);
If you want the code that is execute regularly to be the same code that a route uses, then put that code in a function and call that function from both the interval timer and from your route. To fully automate an actual route call, you'd have to make a request to your own http server that would create the request and response objects for you, but that is probably not what you really need to do.

Routes with parameters gets called twice?

I am creating a NodeJS web application via ExpressJS. I have the following two routes (among others):
app.get('/user/reset/verify', function(req, res) {
console.log("Executing verification index.");
res.render("verify/index");
});
app.get('/user/reset/verify/:email/:token', function(req, res) {
console.log("Executing verification change.");
res.render("verify/change");
});
When I go to the verification index page, I see "Executing verification index." printed once on the console. However, when I go to the verification change page, I see "Executing verification change." printed twice on the console.
I have noticed that this is a trend with the routes in my app. Routes that contain parameters are always executed twice, while routes without parameters are only (properly) executed once.
Why are the routes with parameters being executed twice?
The views that are being rendered only contain simple HTML - nothing that would cause another request to the page. Also, I am issuing these requests from a Chrome browser.
Platform/Versions:
NodeJS: 0.5.5 windows build (running on Win 7)
Express: 2.4.6
Connect: 1.7.1
The second request is the /favicon.ico
Try to console log your request.url in your http_server request handler, you'll see the first is the browser url and the next the favicon.
If you are using chrome:
When you write your url chrome send a get request to check the url before you hit enter.
Try to log the middleware url console.log(req.url) position your console aside your broswer then start to write the url, you will see console logging a get access.

Resources