This section continues with the Router module, starting with the most commonly used use.
router.use
The source code of the method is as follows:
proto.use = function use(fn) { var offset = 0; var path = '/'; if (typeof fn !== 'function') { var arg = fn; while (Array.isArray(arg) && arg.length !== 0) arg = arg[0]; if (typeof arg !== 'function') { offset = 1; path = fn; } } var callbacks = flatten(slice.call(arguments, offset)); if (callbacks.length === 0) throw new TypeError('Router.use() requires a middleware function') for (var i = 0; i < callbacks.length; i++) { var fn = callbacks[i]; if (typeof fn !== 'function') throw new TypeError('Router.use() requires a middleware function but got a ' + gettype(fn)) debug('use %o %s', path, fn.name || '<anonymous>'); // Internal module layer! var layer = new Layer(path, { sensitive: this.caseSensitive, strict: false, end: false }, fn); // adopt use Method generated layer No, route value layer.route = undefined; // Array defined at initialization this.stack.push(layer); } return this; };
The first half is familiar with app.use.
Of course, the final traversal of middleware function processing is different, introducing a new local module, Layer.
Layer
I don't quite understand the meaning of this layer. Whether app.use or router.use, each middleware generates a layer object and push es it into the stack array on the router.
What about multipaths? Do they generate multiple layer s? The answer is No.
Look at the layer constructor:
function Layer(path, options, fn) { if (!(this instanceof Layer)) { return new Layer(path, options, fn); } debug('new %o', path) var opts = options || {}; /** * layer.handle => Middleware function * layer.name => Function name * layer.regexp => The Rule of Path */ this.handle = fn; this.name = fn.name || '<anonymous>'; this.params = undefined; this.path = undefined; this.regexp = pathRegexp(path, this.keys = [], opts); // Fast Matching Marker this.regexp.fast_star = path === '*' this.regexp.fast_slash = path === '/' && opts.end === false }
The key step is to generate a rule according to the incoming path. pathRegexp is a tool module, which can return a value needed for regular matching regardless of the string, array or regularity passed in.
A brief look at the tool core source code:
function pathtoRegexp(path, keys, options) { // ... // Character string path = ('^' + path + (strict ? '' : path[path.length - 1] === '/' ? '?' : '/?')); // ...There are many behind. replace // array if (Array.isArray(path)) { path = path.map(function(value) { return pathtoRegexp(value, keys, options).source; }); // Use|Segmentation of multiple rules for multiple matching return new RegExp('(?:' + path.join('|') + ')', flags); } // Regular is simpler // var MATCHING_GROUP_REGEXP = /\((?!\?)/g; if (path instanceof RegExp) { // Matching group while (m = MATCHING_GROUP_REGEXP.exec(path.source)) { keys.push({ name: name++, optional: false, offset: m.index }); } return path; } }
String mode is very complex, because the parsing of strings that allow regular writing of classes becomes very complex. There are a lot of replace ments behind them. Here's a beginning. It's simpler and more addictive.
Finally, a regular expression matching the path is returned, and then two tags are added to the object. For example, if a Layer's regular object has a global routing tag, the middleware can be invoked directly without regular checking at all.
When the Layer object is returned, it is push ed into the stack array of router s.
This section briefly looks at the Router module's use method, and the next section looks at the source flow of the specific request method.