About next mainly from three points to explain:
- What's the role of next?
- When should we use next?
- What is the internal implementation mechanism of next?
The role of Next
When we define the Express middleware function, we define the third parameter as next, which is our main character today, the next function is responsible for handing control over to the next middleware, and if the current middleware does not have an end request and next is not called, then the request will be suspended. The middleware defined behind it will not be able to be executed.
When to use next
From the top of the description we already know that the next function is mainly used to ensure that all the registered middleware is executed one by one, then we should call the next function in all middleware, but there is a special case, if we define the middleware to terminate this request, then we should not call the next function, Otherwise it could be a problem, let's see the code.
App.Get('/A ', function(Req,Res, Next) {Res.Send(' Sucess '); Next();});Catch 404 and forward to error handlerApp.Use(function(Req,Res, Next) {Console.Log(404); VarErr= New Error(' Not Found ');Err.Status= 404; Next(Err);});App.Use(function(Err,Req,Res, Next { Res. (err. Status | | 500); Res. ( ' ERROR ' , {< Span class= "PLN" > Message: Err., Error: {}< Span class= "PLN" > ); });
To send the request "/a", the console print log is as follows:
404GET /a 500 6.837 ms - -Error: Can‘t set headers after they are sent. at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:345:11)
Why the code throws an exception, because we call the next function after Res.send, although our request has been terminated, but the back of the 404 middleware will still be executed, the second side of the middleware to the RES headers to add property values, so it will throw the top exception.
Read this you may have a question, if I do not call the next function behind Res.send, then the definition of the 404 middleware will never be executed to. Now we delete res.send next function call, send the request "/xxx", we will find that 404 middleware is executed, (ㄒoㄒ), this is not the contradiction we said before, our custom middleware does not call next, but the definition behind the middleware is still executed, What the hell is this? It seems that only the source of Help ~ ~ ~
The internal mechanism of next
function Next(Err) { ... The source code is omitted here Find Next matching layer VarLayer; VarMatch; VarRoute; While (Match!== True &&Idx<Stack.Length) {Layer=Stack[Idx++];Match=Matchlayer(Layer,Path);Route=Layer.Route; If (typeofMatch!== ' Boolean ') { Hold in to LayererrorLayererror=Layererror||Match; } If (Match!== True) { Continue; } ... The source code is omitted here }... The source code is omitted here This should is done for the layer If (Err) { Layer. (err, Req , Res, next} else {. Handle_request (req, res , next); } } /span>
Above is the source of the next in Express, in order to more easily explain the problem, the code was truncated. From the source above can be found that the next function has a while loop, each cycle will be taken from the stack a layer, the layer contains the routing and middleware information, and then the layer and the requested path to match the line, If the match succeeds, the Layer.handle_request is executed and the middleware function is called. But if the match fails, the next layer (i.e. middleware) is looped.
Now we can explain the question raised above, why our custom middleware does not call the next function, but the back of the 404 middleware will still be executed, because the "/xxx" we requested does not match our registered "/a" routing middleware, so the while loop will continue to execute, Matching 404 middleware succeeds, so 404 middleware is executed.
Note: App.use registered middleware, if the path parameter is empty, the default is "/", and the middleware with path "/" matches all requests by default.
It is important to point out that in fact, when we define the routing middleware, the third parameter of the function next and we define the non-routed middleware function of the third parameter next is not the same next, we see on the top of the non-routing middleware next, and the next function of the routing middleware is this
function Next(Err) { If (Err&&Err=== ' Route ') { Return Done(); } VarLayer=Stack[Idx++]; If (!Layer) { Return Done(Err); } If (Layer.Method&&Layer.Method!==Method) { Return Next(Err); } If (Err) { Layer. (err, Req , Res, next} else {. Handle_request (req, res , next); } } /span>
This next is much simpler than the next one, which is responsible for the control of multiple middleware in the same route, and it receives a parameter "route" that, if called next ("Route"), skips over the other middleware of the current route, handing control over to the next route directly.
Finally, it is necessary to say next (err), Next (Err) is how to pass control to the error-handling middleware, from the front of the code we know that when calling next (Err) is, express internally will call Layer.handle_error, Well, let's take a look at its source.
Layer.Prototype.Handle_error= functionHandle_error(Error,Req,Res, Next) { VarFn= This.Handle; If (Fn.Length!== 4) { Not a standard error handler Return Next(Error } try { Fn (error, Req, Res, next } catch (err) { err}};
The FN in the code is the middleware function, Express will determine the number of FN parameters, if the parameter number is not equal to 4 is not the error processing middleware, then continue to call next (err), so that will go to the next middleware function, the number of arguments to continue to judge, In this way until the number of parameters of a middleware function is 4, it is considered that the error-handling middleware is found and then executes this middleware function.
Essence's understanding of the next function in Express