7 - Router module of express source code (3)-app[METHODS]

Keywords: Javascript Attribute

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

Posted by healthnut on Sun, 06 Jan 2019 16:45:09 -0800