Reputation: 2160
I'm wondering what the mechanics behind the behaviour of the following code are:
res.send(200, { data: 'test data' });
console.log('still here...');
My understanding is that res.send
doesn't return the function, but does close the connection / end the request. This could explain why I can still execute code after a res.send
command (I looked through the express source and it doesn't seem to be an asynchronous function).
Is there something else at play that I may be missing?
Upvotes: 115
Views: 67863
Reputation: 83
I had a similar issue but the answers provided and the comments helped. Here's my two cents. The code that comes after res.send() still runs although the connection with the client gets closed. In my context, I had a function that checked whether a user existed in my MongoDB db and then return the user else return null.
export const authenticateUser = async (req: Request, res: Response) => {
const {username, password} = req.body as IUser
const user = await getUser(username) // returns user or null
if(user === null){
console.log("user is null")
res.status(404).send("user not found")
}
// if user is null the connection get's closed since the above if block runs
// but since res.send() doesn't end the function the code below continues to run
// this causes an error because user is null
const passwordMatch = await compare(password, user!.password)
if(!passwordMatch){
res.status(400).send("wrong password")
}
}
adding an else block should solve this
export const authenticateUser = async (req: Request, res: Response) => {
const {username, password} = req.body as IUser
const user = await getUser(username) // returns user or null
if(user === null){
console.log("user is null")
res.status(404).send("user not found")
}else{
const passwordMatch = await compare(password, user!.password)
if(!passwordMatch){
res.status(400).send("wrong password")
}
}
}
Upvotes: 0
Reputation: 4463
A possible solution is with this library: on-finished
var destroy = require('destroy')
var fs = require('fs')
var http = require('http')
var onFinished = require('on-finished')
http.createServer(function onRequest (req, res) {
var stream = fs.createReadStream('package.json')
stream.pipe(res)
onFinished(res, () => {
destroy(stream)
})
})
Works with Express too, for example:
const express = require('express');
const app = express();
app.get('/video', (req, res) => {
const ffmpeg = spawn(ffmpegPath, argsArray);
ffmpeg.stdout.pipe(res);
onFinished(res, () => {
ffmpeg.kill();
});
});
Upvotes: 0
Reputation: 145002
Sure end
ends the HTTP response, but it doesn't do anything special to your code.
You can continue doing other things even after you've ended a response.
What you can't do, however, is do anything useful with res
. Since the response is over, you can't write more data to it.
res.send(...);
res.write('more stuff'); // throws an error since res is now closed
This behavior is unlike other traditional frameworks (PHP, ASP, etc) which allocate a thread to a HTTP request and terminate the thread when the response is over. If you call an equivalent function like ASP's Response.End
, the thread terminates and your code stops running. In node, there is no thread to stop. req
and res
won't fire any more events, but the code in your callbacks is free to continue running (so long as it does not attempt to call methods on res
that require a valid response to be open).
Upvotes: 171
Reputation: 1176
Edit: I no longer do what is explained below, as you shouldn't return a value when there is no need for it. It makes your code less readable and looks hackish. Instead, I suggest separating the return statement from the res.send()
. @slavafomin explained this well in the comments.
A simple way to stop the execution of the function and send a response at the same time is by doing
return res.send('500', 'Error message here');
This allows you to use short if
statements to handle errors such as:
if (err) {
return res.send('500', 'Error message here');
}
The exact return of the res.send
function is an object that seems to contain the entire state of the connection after you ended it (request, status, headers, etc.), but this should be unimportant since you won't be doing anything with it.
Upvotes: 54