Sending multiple HTTP responses with Express.js

The Express.js framework simplifies the task of creating a Node.js web server. When crafting your response to the user, the send method of the Express response object is a powerful tool. It provides abstraction for sending the response. This includes setting the appropriate content-type header, and then ending the response process. That is a lot, and it is helpful.

But what about when you want to send more than one response? The send method of the Express response object ends the response process. This poses a problem when the back-end wants to send more than one response. In this article, I will give an example of the problem, and a way to work around it.

To get started, clone the following git hub repository:

https://github.com/kevinchisholm/sending-multiple-http-responses-with-express.js

(Instructions on how to run the code are available in the Git hub page.)

package.json

{
  "name"         : "sending-multiple-http-responses-with-express.js",
  "version"      : "1.0.0",
  "description"  : "Sending multiple HTTP responses with Express.js.",
  "author"       : "Kevin Chisholm",
  "dependencies" : {
    "express": "4.14.0"
  }
}

The package.json for this project is simple. For this article, we need the express and no other dependency.

Trying to use the response.send method more than once per request.

Example # 1:

//require the express nodejs module
var express = require('express'),
  //set an instance of exress
  app = express();
 
//tell express what to do when the / route is requested
app.get('/', function (req, res) {
  var i = 1,
    max = 5;
 
  //set the appropriate HTTP header
  res.setHeader('Content-Type', 'text/html');
 
  //send multiple responses to the client
  for (; i <= max; i++) {
    res.send('<h1>This is the response #: ' + i + '</h1>');
  }
});
 
//wait for a connection
app.listen(5000, function () {
  console.log('The web server is running. Please open http://localhost:5000/ in your browser.');
});

Run example # 1 in your terminal with the following command: node example-1.js. Then point your browser to: http://localhost:5000/.

The result of this is: you will see this in your browser: "This is the response #: 1"

In example # 1, we have a for loop. The purpose of this for loop is to imitate a dynamic back-end. Imagine that your Node.js web server needs to act-upon some data. There could be one record in that data set, or 10,000 records. We don't know the exact amount. We just want to send a response to the user for each row in the data set.

There are two problems with Example # 1. The first problem is that any responses after the first one are never sent. This is because the send method of the Express response object ends the response process. As a result, the user never sees the messages "This is the response #: 2" or "This is the response #: 3", and so forth. The second problem is that the send method of the Express response object sets the Content-Type header. This is automatic. But, we have already set the Content-Type header. Because of this, the send method will throw this error: "Error: Can't set headers after they are sent."

Using the result.write method

Example # 2:

//require the express nodejs module
var express = require('express'),
  //set an instance of exress
  app = express();
 
//tell express what to do when the / route is requested
app.get('/', function (req, res) {
  var i = 1,
    max = 5;
 
  //set the appropriate HTTP header
  res.setHeader('Content-Type', 'text/html');
 
  //send multiple responses to the client
  for (; i <= max; i++) {
    res.write('<h1>This is the response #: ' + i + '</h1>');
  }
});
 
//wait for a connection
app.listen(5000, function () {
  console.log('The web server is running. Please open http://localhost:5000/ in your browser.');
});

Run example # 2 in your terminal with the following command: node example-2.js. Then point your browser to: http://localhost:5000/.

The result of this is: you will not see any of the messages in the browser.

There is still a problem with example # 2: the response is never complete. Open up your developer tools (e.g. FireBug or Chrome Dev Tools), and then look at the network tab. You'll see that all five responses did in-fact come back to the client. The problem is, the browser is waiting for more responses. At some point, the request should time out and you can see all messages in the browser. This behavior can vary between browsers, but it is not the correct experience.

result.end saves the day.

Example # 3:

//require the express nodejs module
var express = require('express'),
  //set an instance of exress
  app = express();
 
//tell express what to do when the / route is requested
app.get('/', function (req, res) {
  var i = 1,
    max = 5;
 
  //set the appropriate HTTP header
  res.setHeader('Content-Type', 'text/html');
 
  //send multiple responses to the client
  for (; i <= max; i++) {
    res.write('<h1>This is the response #: ' + i + '</h1>');
  }
 
  //end the response process
  res.end();
});
 
//wait for a connection
app.listen(5000, function () {
  console.log('The web server is running. Please open http://localhost:5000/ in your browser.');
});

Run example # 3 in your terminal with the following command: node example-3.js. Then point your browser to: http://localhost:5000/.

The result of this is: you will see all of the messages in the browser.

In example # 3, we have fixed the problem. We use response.write to send more than one message back to the client. When the for-loop completes, we use the result.end method to end the response process. This tells the browser: "we're done, go ahead and render the response".

Summary

In this article, we learned how to send more than one HTTP responses with Express.js. We discussed how result.send is helpful, but problematic when we want to send more than one response. We then walked-through the solution. We used response.write to send more than one response, and then used result.end to manually end the response process.

Author

Kevin Chisholm

http://blog.kevinchisholm.com

Share This