How to end an express.js / node POST response? - node.js

Im trying to just stop the post request after I've saved a document to the DB, ie:
app.post('/blah'), function(req,res){
//my code does a bunch of stuff
res.what do i put here to tell the client browser to just... stop the POST
}
At the moment im simply using res.redirect('back') which works, but the page refresh is totally arbitrary and i would prefer it didnt happen. I had a go at res.end(); but that sends the client to a blank page...
Thanks in advance.
edit:
I dont think i made myself clear enough in what im doing sorry.
Perhaps its bad practice but this is whats happening:
POST initiates database save function
Browser sits around waiting for a response
When its good and ready, the obj is saved to the DB, then a callback triggers a NowJS function, which adds the item to the view(for everyone)
I did it this way to be non-blocking( so i thought)

You can use res.end and pass in a string that you want to be sent to the client:
res.end('It worked!');
Alternatively, you could render a view and then end the response:
res.render('blah.jade');
res.end();
All that said, redirecting the client is actually the best practice. It makes it so that when they hit the back button in their browser, they can move back seamlessly without getting any "POST required" popups or the like. This is the POST/redirect pattern and you can read more about it at http://en.wikipedia.org/wiki/Post/Redirect/Get.

For future reference, you can also do:
res.redirect('back');
Basically this just redirects the browser back to the screen the request came from, in other words "refreshing" it. It's hacky and I wish there was a better way, but it works.

While you can use the underlying end method borrowed from Node's http module, Express.js has its own send method that calls end when appropriate:
/**
* Send a response.
*
* Examples:
*
* res.send(new Buffer('wahoo'));
* res.send({ some: 'json' });
* res.send('<p>some html</p>');
* res.send(404, 'Sorry, cant find that');
* res.send(404);
*
* #param {Mixed} body or status
* #param {Mixed} body
* #return {ServerResponse}
* #api public
*/
res.send = function(body){
.
.
.
// respond
this.end(head ? null : body);
return this;
};

Use --> res.status(204).send(); inside the post request
if(err) {
console.log(err);
} else {
res.status(204).send();
}

If you could modify your client side code to make the post request via AJAX, you could simply use res.end().
The problem here is that when the browser makes a POST request (not via AJAX), it no longer cares about the current page. It is expecting a new page, so it will load a new page. This is purely with the browser, and I do not believe there is currently a way for you to work around it.
Overall, you should just use an AJAX POST request if you can.

The client browser is waiting for a response. So why not give it one with something like res.send('<p>Thank you</p>'); or a nice rendered view?
The reason res.end() sends the client to a blank page is that you aren't giving the client anything to display.

The best way to end the express routing without routing to new page or what ever the mess express want you not to stay on the current page although you have your own reason is to use window.stop, for example a form, you use javascript to handle the submission, the timeout should be enough to ensure the data is send as POST method.
document.myform.mysubmit.click()
setTimeout(function(){
window.stop()
}, 3000);

Related

Good practice to handle useless response in express js/nodejs?

Am using express js on node for my api service ! In which am using sequelize for query handling purposes !
So in some usecase like creating record, or updating record its simply returning "1" or sometimes nothing !
In this case , am just using
res.sendStatus(200);
or sometimes
res.send("success");
Is there any better way or this is the correct way to handle ? Or should in need .end() in order to end the process ??
which is a good way to handle these kind of useless responses which we dont need to send back ?
This is where Status 204 comes in to play: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#2xx_success
It states: everything is OK (like in 200), but there is simple no need to send a body.
Using express, it's just as simple as: res.sendStatus(204)
Usually a json is send back to the client with different information in it that lets the client-side know that the operation that they request through the api is successfull or failed. for e.g. here, you can define a standard json response like this
//in case of success of the request
{
requestStatus: 1,
...other data if you want to like new Id of the created data/updated data or info about it if you want or depending upon use case
}
or
// in case of failure of the request
{
requestStatus: 0,
...other data if you want to like reason for failure, error message or depending upon your use case
}
Just add this line of code, should be fine:
//For all bad endpoints
app.use('*', (req, res) => {
res.status(404).json({ msg: 'Not a good endpoint, why are you here? Go play FIFA.'})
})
If you want you can generate an error HTML file, but since it's back-end, JSON format is strongly suggested. You can also add success: false for more clarity.

node async call return data in response

I am new to nodejs so I have a basic question and this is my scanrio
I have a javascript client which is making a http request to a node server to read a value from the database.
Once the node server receives the request it makes a simple db call and returns the data to the client in the response, and this is where the problem is.
router.get('/state', function(req, res){
var result = dbServer.makeDBCall();//Before this line executes and returns the result the next line executes
res.send(result);
}
The database call from the node server is asynchronous, therefore before the result is returned the node server has already sent a blank response to the client. What is the standard/acceptable way of getting this achieved, I know I can block the node thread using async, but then the whole purpose of node is gone right?
It depends on what kind of database node module you are using.
Other than the standard callback approach, there are also the promise way. The pg-promise library is 1 of those kind.
See sample code:
this.databaseConnection.makeDBCall('your query...')
.then(function(dbResponse) {
// Parse the response to the format you want then...
res.send(result);
})
.catch(function(error) {
// Handle error
res.send(error.message);
});
#spdev : I saw 1 of your comments about you being worried about how Node actually knows who to reply the response to, especially when there are multiple requests.
This is a very good question, and to be honest with you - I don't know much about it as well.
In short the answer is yes, Node somehow handles this by creating a corresponding ServerResponse object when a HTTP request comes through. This object seems to have some smartness to tell the Nodejs network stack how to route itself back to the caller when it gets parsed as data packets.
I tried Googling a bit for an answer but didn't got too far. I hope the ServerResponseObject documentation can provide more insight for you. Share with me if you got an answer thanks!
https://nodejs.org/api/all.html#http_class_http_serverresponse
Try below code.
router.get('/state', function(req, res){
var result = dbServer.makeDBCall(function(err,result){
if(!err) {
res.send(result);
}
});
}
Hope this Help.
The dbServer.makeDBCall(); must have a callback that runs when the statement completes executing.
Something like -
dbServer.makeDBCall({query: 'args'}, function(err, result){
if (err) // handle error
res.send(result);
})
You return the response from db from that callback function.
Learn more about callback from here-
nodeJs callbacks simple example
https://docs.nodejitsu.com/articles/getting-started/control-flow/what-are-callbacks/

Error: Can't set headers after they are sent only on page refresh

I have this problem only when I try refresh the page and I can not solve it, I tried everything but still happens the same. It began to happen when I add socket.io at the project. The project run in several servers which are connected one each other throught sockets.
TEST CASES: When I render the page, at the first time everything goes well but, if I refresh the same page, I get this error:
ERROR: "Error: Can't set headers after they are sent. at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:344:11)"
ATTENTION: when get in IF() and send "return res.end('The Activation Code is INVALID!');" it DOESN'T HAPPEND! I refresh it and refresh it and everything goes well. My problem is in the RENDER.
MY CODE BELOW:
activationUser = function(req,res,next){
var data = {
activationCode : req.params.activationCode,
now : new Date().valueOf(),
ip : req.connection.remoteAddress,
fId : frontalId
}
socketCore.emit('activationUser', data);
socketCore.on(frontalId + 'activationUserResp', function(data){
if(data.msg == "CHECKED!"){
next();
}else{
return res.end(data.msg);
}
});
}
router.get('/activationUser/:activationCode',activationUser,function(req,res){
var data = {
activationCode : req.params.activationCode,
fId : frontalId
}
socketCore.emit('step2', data);
socketCore.on(frontalId + 'step2Resp', function(data){
if(data.msg == 'err'){
return res.end('The Activation Code is INVALID!');
}else{
return res.render('registro2', {title: 'title | '+ data.name + ' ' + data.lastname, user:data});
}
});
});
Thank you!
The particular error you are getting happens when you try to send anything on the res object after the complete response has already been sent. This often occurs because of errors in asynchronous logic. In your particular case, it apepars to be because you are assigning a new event handler with socketCore.on() every single time the router is hit. Those event handlers will accumulate and after the first time the route is hit, they will execute multiple times triggering the sending of multiple responses on the same response object, thus trigger that error.
The main ways to fix your particular problem are:
Use .once() instead of .on() so the event handler automatically removes itself after being triggered.
Manually remove the .on() event handler after you get the response.
Move the event handler outside of the route so it's only ever installed once.
In your particular case, since socketCore is a shared object available to all requests, it appears that you also have a race condition. If multiple users trigger the '/activationUser/:activationCode' route in the same general time frame, then you will register two event handlers with socketCore.on() (one for each route that is hit) and you will do two socketCore.emit('step2', data);. But, you have no way of associating which response belongs with which request and the two responses could easily get mixed up - going to the wrong request.
This highlights how socket.io connections are not request/response. They are message/answer, but unless you manually code a correspondence between a specific message request and a specific answer, there is no way to correlate which goes with which. So, without assigning some particular responseID that lets you know which response belongs to which message, you can't use a socket.io connection like this in a multi-user environment. It will just cause race conditions. It's actually simpler to use an HTTP request/response for this type of data fetching because each response goes only with the request that made it in the HTTP architecture.
You can change your architecture for making the socketCore request, but you will have to manually assign an ID to each request and make sure the server is sending back that ID with the response that belongs to that request. Then, you can write a few lines of code on the receiving side of things that will make sure the right response gets fed to the code with the matching request.

nodeJS prevent timeout on res.download

I have a POST call to my nodeJS server that searches for some data on the mongo database and returns a CSV file with the requested data. The problem is that the data search and processing exceeds the 2 minute nodeJS default timeout.
On a diferent scenario y used:
res.writeHeader(200,'application/json');
res.write('starting fetch .... ');
to keep alive the request and prevent the timeout from the client by sending some res.write(''); from time to time.
Now Im using res.download() to download the resulting csv file, so not just sending JSON as response.
Tried to use this solution like this:
res.writeHeader(200,'application/json');
res.write('starting fetch .... ');
res.download()
But i get the "headers already sent" error.
Any idea on how to prevent the timeout until the data is processed and the file download is done ?
Thanks in advance
A few small things first of all, i think it's supposed to be res.writeHead() instead of res.writeHeader(). Secondly once you send the headers you can not send them again. You are getting the error because res.download() uses res.sendFile() which re-sends the headers. You can't use res.download() or res.sendFile() or res.send() because all of these three methods implicitly set the headers and send as part of the response. You'll need to use a combination of res.writeHead() ,res.write() and res.end(). I am just GET so i can test it from the browser, you can use post obviously.
router.get('/test', function (req,res,next) {
res.writeHead(200, {'Content-Type': 'application/json',
'Content-Disposition': 'attachment',
'filename':'package.json'
});
fs.readFile("package.json",function (err,data) {
if (err) {
throw err;
}else{
setTimeout(function () {
res.write(data);
res.end()
},200000);
}
});
function keepBusy(){
if(!res.finished){
res.writeProcessing();
setTimeout(keepBusy,1000)
}
}
setTimeout(keepBusy,1000);
});
This works fine for me. res.writeProcessing() sends the 102 status code. It is recommended for requests that last greater than 20 second but this blog post says that
102 has been left out more recent revisions of HTTP specifications
but it works fine for me in most browsers. If you have some control over the client as well there can be a much better and reliable solution.

Simple Hello World Issue in Node.js

I'm new to node.js and have this very simple code. I just want to say a Hi User every second to the users who have connected to the server.
Here's the code I have:
var http = require('http');
function newfunc(request, response) {
response.writeHead(200, {
"Content-Type": "text/plain",
"connection" : "keep-alive"
});
setInterval(function() {
response.write('Hi User\n');
response.end('');
}, 1000);
}
http.createServer(newfunc).listen(7070);
I see the Hi User message only once, and seems as if setInterval is writing it only once.
What am I doing wrong in this?
EDIT: I stand corrected in the comments... Just remove the response.end() call and you should see something like what you were expecting.
ORIGINAL RESPONSE: What you are trying to do cannot be done in this fashion... The response to an HTTP request is only ever sent once: when response.end() is called (the first time). Commenter points out that this is not really correct: what would be correct to say is that no further data can be sent in the response after end() is called.
If you want to show an HTML page whose contents change every second based on server-side actions, you will need to use something like WebSockets (e.g. the Node-compatible http://socket.io/ library) and some client-side Javascript, which is somewhat more complicated than the code you have above. In general, for non-trivial UI's that do more than just append to the response or do bi-directional communication, this type of approach is preferrable

Resources