response.send() sends the response and closes the connection, whereas with response.write() you can send multiple responses.
In this article, I will explain the difference between response.send(), response.end() and response.write(), and when to use each one. When you’re working with the Express.js framework, you’ll probably most frequently be sending a response to a user. This means that regardless of which HTTP verb you’re handling, you’ll pass a function as the handler for that endpoint. This function will receive two arguments: the request object and the response object. The response object has a send() method, an end() method and a write() method, and in this article we’ll get to know the differences between them.
So, let’s start with the main issue, which is that the response.send() method is used to send the response to the server. Now this makes sense and in some cases, it’s actually the perfect tool. Problems can arise, though, if you’re not entirely sure what the response.send() method actually does. Well, in a nutshell, it does two things; it writes the response and also closes the connection. So, this seems like a win-win, right? Well, in some cases it is, but if you don’t want to close the connection on your first write, then the response.send() method may not be the right tool. When this happens, you’ll need to use a combination of response.write() and response.close(). So, let’s take a look at a few examples, to see just how this works.
Get the example code from GitHub
If you clone this repo: github.com/kevinchisholm/video-code-examples/tree/master/node-express/response-send-end-write-difference, you can clone the example code locally and edit the code yourself.
Trying to use the response.send method more than once per request – Example # 1
Run Example # 1 in your terminal with the following command: node example-1.js, then point your browser to: http://localhost:5000/. Now you’ll see this: “This is the response #: 1“. There are two problems here, however, the first of which is that any responses after the first one are never sent. This is because the send method of the Express.js 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, which is an automatic action. So, on the first iteration of the for-loop, the Content-Type header is set (i.e. “This is the response #: 1”). Then on the next iteration of the for-loop, the Content-Type header is set again because once more, we are using the response.send() method (i.e. “This is the response #: 2). But, we have already set the Content-Type header in the first iteration of the for-loop.
Because of this, the send method will throw this error: “Error: Can’t set headers after they are sent”. So, our application is essentially broken, but we don’t want users to have an error in their consoles. And more importantly; our back-end logic is not working correctly.
Using the result.write method – Example # 2
So, using the result.write method run Example # 2 in your terminal with the following command: node example-2.js. Now point your browser to: http://localhost:5000/. As you can see, there is still a problem with our code. Depending on your browser, either you will see only the first message or you will see none of them. This is because the response has not been completed. So, I’ll just mention here, that not every browser handles this case the same, which is the reason why you may see one message, all of the messages or none of them. But you should see that the request is “hanging” as your browser will stay in that “loading” state.
So, open 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 fixes the problem – Example # 3
Run Example # 3 in your terminal with the following command: node example-3.js, then point your browser to: http://localhost:5000/. You will now see all of the messages in the browser, which means that here, in Example # 3, the problem has been fixed. We see all of the messages generated by the for-loop and the response completes successfully with no console errors. So, we’ve solved the problem by using a combination of of response.write() and response.close().
First we set the Content-Type header, just to get that task out of the way. Then, in each iteration of the for-loop, we used response.write() to send a message back to the client. But since response.write() does not set any headers or close the connection, so we were free to call response.write(), to send another response to the client. And once the for-loop was completed, we used the result.end() method to end the response process (i.e. we closed the connection). This said to the browser: “we’re done; go ahead and render the response now and don’t expect anything more from me.”
Summary
In this article, we learned about the difference between response.send(), response.end() and response.write(). During this discussion, we found that response.send() is quite helpful in that it sends the response and closes the connection. We saw that this becomes problematic, however, when we want to send more than one response to the client. But, fortunately, we discovered that this is easily solved by using a combination of response.write() and response.close(). We used response.write() to send more than one response, and then used response.end() to manually end the response process and close the HTTP connection. So, useful steps and easily solved problems.!