Previous discussions were limited to the use method, and requests in all ways were passed. This section discusses how special request methods are handled within express.
Give me a flow chart.
app.METHODS and router.METHODS:
// app.use methods.forEach(function(method) { // app.get,app.post... app[method] = function(path) { if (method === 'get' && arguments.length === 1) { // app.get(setting) return this.set(path); } // Here this.lazyrouter(); // Generate a route object var route = this._router.route(path); // call route Method route[method].apply(route, slice.call(arguments, 1)); return this; }; }); // router.use methods.concat('all').forEach(function(method) { proto[method] = function(path) { var route = this.route(path) route[method].apply(route, slice.call(arguments, 1)); return this; }; });
Generally the same, the only strange thing is that app.all method is defined separately in app module. Although the content is only to traverse the corresponding method of METHODS array invocation, it is not more elegant than to let route handle directly. (Asked the developer this question, got the answer, super happy! )...
router.route
The two methods mentioned above all point to the route method of the router module, and the source code is as follows:
proto.route = function route(path) { // new One Route object var route = new Route(path); // new One Layer object var layer = new Layer(path, { sensitive: this.caseSensitive, strict: this.strict, end: true }, route.dispatch.bind(route)); // In this form Layer Yes route attribute layer.route = route; // same push reach stack in this.stack.push(layer); return route; };
Here, a route object and a layer object are successively generated. Because only the path is passed in, the layer's middleware becomes a route built-in method, regardless of it for the time being.
Route
Here's a look at the constructor of the route object:
function Route(path) { this.path = path; this.stack = []; debug('new %o', path) // Method sets with different request modes this.methods = {}; }
Very simply, the headache is that each route also has a stack.
After returning the route instance, the corresponding method of route is called and passed into the middleware function.
There's a problem with app[METHODS](function...). Normally, app.use direct transfer function is equivalent to matching the middleware for all paths, but if the request method is specified, the code is invalid. Although the process is error-free and very smooth, it finally returns a useless route object, which opens on the evening of April 18. The sender sent another e-mail to ask this question. As of the morning of the 19th, he hadn't answered me yet.
route[method]
Despite all this, the route[method] source code is as follows:
methods.forEach(function(method) { Route.prototype[method] = function() { // Flattening parameters var handles = flatten(slice.call(arguments)); // Traversal Middleware for (var i = 0; i < handles.length; i++) { var handle = handles[i]; // There's still error detection. if (typeof handle !== 'function') { var type = toString.call(handle); var msg = 'Route.' + method + '() requires a callback function but got a ' + type throw new Error(msg); } debug('%s %o', method, this.path); // Method Level Layer Objects don't care about paths var layer = Layer('/', {}, handle); // More than one attribute layer.method = method; // Markup object this.methods[method] = true; // This is route Of stack this.stack.push(layer); } return this; }; });
The steps here need to be sorted out a little:
1. app[method]/router[method] method finally points to router's route method
2. router.route generates a route object and a Layer object based on the path, mounts the route as an attribute on the layer, and the layer object is push ed into the stack array of routers.
3. Calling the method method method corresponding to route, the method traverses the incoming middleware function. Each middleware generates a layer object that ignores the path, and the layer has a method attribute. Finally, push the layer object into the route object.
route.dispatch
In a word, the process has been sorted out. Next, I will add the handle function of the layer object on the router object: route.dispatch.
Route.prototype.dispatch = function dispatch(req, res, done) { var idx = 0; var stack = this.stack; // No if (stack.length === 0) { return done(); } // Method of obtaining requests var method = req.method.toLowerCase(); // unregistered head Mode monitoring head The request shall be deemed as get if (method === 'head' && !this.methods['head']) { method = 'get'; } req.route = this; next(); function next(err) { if (err && err === 'route') return done(); if (err && err === 'router') return done(err); // Remove the corresponding Middleware var layer = stack[idx++]; if (!layer) return done(err); if (layer.method && layer.method !== method) return next(err); if (err) { layer.handle_error(err, req, res, next); } else { // Real approach layer.handle_request(req, res, next); } } };
The stack in the source code is a layer array. When there is a request, one of them will be taken out each time, and then matched with the layer.method. Finally, the middleware is called to process the request.
End of the day 65507