Node.js Can't set headers after they are sent. When initiating an XHR request within another XHR request
Asked Answered
N

1

0

Node.js can't handle my client code that performs something similar to jQuery/Zepto XHR pattern below:

$.ajax({
  type: 'POST',
  url: '/someUrl',
  success: function(response) {
     $.ajax({  // ... do another XHR

I've done this (initiating an XHR request within another XHR request) pattern before within other frameworks. I've read about Node.js Error: Can't set headers after they are sent and how the event-based model of Node.js server works. In other words, the first XHR request hasn't called res.end() so when the second XHR request is called Node.js complains (in a continuous loop btw).

My questions are: Would anyone be able to recommend an alternative pattern to chaining XHR requests client-side? Is there something I can do Node.js server-side to keep the existing client-side pattern?

Update Based On Accepted Answer
The mistake is certainly in my own server side code. A simple validation function was throwing an error but upon catching it, only res.end() was called. For some reason the assumption I had was calling res.end() would immediately stop the execution of the function. In this case, inserting a 'return' stops execution immediately after sending the JSON message to the client.

if (_.isEmpty(req.body)) {  
  res.end(JSON.stringify({'Error':'POST required'}));
  // suppose 'return' is needed here as well
  return
} else {      
  try {
    if (_.has(req.body, 'id')) {
      id = parseInt(req.body['id']);
    } else {
      throw {'Error':'Missing param in req.body'};          
    } // end if
  } catch(err) {      
    res.end(JSON.stringify({'Error':'Missing key(s)','Keys':_.keys(req.body)}));
    // without a return here, the code below this 'do some more work' would 
    // be executed
    return
} // end else
// do some more work
// without the above 'return''s the code would
// a) make a database call
// b) call res.end() again!!! <-- bad. 
Namesake answered 17/2, 2012 at 17:22 Comment(2)
Thinking this through some more, an alternative pattern (and admittedly more efficient) is IF the second XHR request is to the SAME server then it is wasteful to open a second connection since one is already open. So instead of thinking of making many separate calls to a backend api (say one to getUsers and another to getProfiles) it may be better to consolidate the disparate data into one XHR request (say getPage?modules=getUsers,getProfiles). Thoughts?Namesake
To be perfectly honest, I think we need to see the back-end code in Node.js to see what's happening, @exshovelrydr. The pattern you describe certainly should work in Node.js, if I'm reading it correctly -- the success callback is called once all of the data has been transmitted by the server, so the Node response object should have already been closed to reach that point, and the second AJAX call shouldn't have an impact.Championship
P
0

The problem is not what you think it is. Your two XHRs happen in serial, not parallel, due to the callbacks. The success callback of the first one won't fire until the entire request/response process is complete for the first request (node.js has already called response.end() and the browser has received and parsed the response). Only then does the second XHR commence. The client side AJAX pattern you have is fine. It will work with node.js and any other web server equally well.

Your problem is in your server side node.js code, but it's not a bug or limitation in node, it's a programming mistake on your part. Post your server side code and we can help you track it down. It is very common for node.js beginners to hit this error with a simple coding mistaking.

Pyxidium answered 18/2, 2012 at 5:52 Comment(1)
Thank you for the explanation. I did a simple test that chained XHR requests to Node.js backend and it worked as expected. I am going to debug my code and see if I can find the error.Namesake

© 2022 - 2024 — McMap. All rights reserved.