router源码学习小结(3)

/** * Returns separate middleware for responding to `OPTIONS` requests with * an `Allow` header containing the allowed methods, as well as responding * with `405 Method Not Allowed` and `501 Not Implemented` as appropriate. * * @example * * ```javascript * var Koa = require('koa'); * var Router = require('koa-router'); * * var app = new Koa(); * var router = new Router(); * * app.use(router.routes()); * app.use(router.allowedMethods()); * ``` * * **Example with [Boom](https://github.com/hapijs/boom)** * * ```javascript * var Koa = require('koa'); * var Router = require('koa-router'); * var Boom = require('boom'); * * var app = new Koa(); * var router = new Router(); * * app.use(router.routes()); * app.use(router.allowedMethods({ * throw: true, * notImplemented: () => new Boom.notImplemented(), * methodNotAllowed: () => new Boom.methodNotAllowed() * })); * ``` * * @param {Object=} options * @param {Boolean=} options.throw throw error instead of setting status and header * @param {Function=} options.notImplemented throw the returned value in place of the default NotImplemented error * @param {Function=} options.methodNotAllowed throw the returned value in place of the default MethodNotAllowed error * @returns {Function} */ Router.prototype.allowedMethods = function (options) { options = options || {}; var implemented = this.methods; return function allowedMethods(ctx, next) { // 所有中间件执行完之后执行allowedMethod方法 return next().then(function() { var allowed = {}; // 没有响应状态码或者响应了404 if (!ctx.status || ctx.status === 404) { // 在match方法中,匹配的路由的layer实例对象组成的数组 ctx.matched.forEach(function (route) { route.methods.forEach(function (method) { // 把匹配的路由的http方法保存起来,认为是允许的http请求方法 allowed[method] = method; }); }); var allowedArr = Object.keys(allowed); // 如果该方法在router实例的methods中不存在 if (!~implemented.indexOf(ctx.method)) { // 如果在初始化router时配置了throw属性为true if (options.throw) { var notImplementedThrowable; if (typeof options.notImplemented === 'function') { // 指定了报错函数 notImplementedThrowable = options.notImplemented(); // set whatever the user returns from their function } else { // 没有指定则抛出http异常 notImplementedThrowable = new HttpError.NotImplemented(); } throw notImplementedThrowable; } else { // 没有配置throw则响应501 ctx.status = 501; // 设置响应头中的allow字段,返回允许的http方法 ctx.set('Allow', allowedArr.join(', ')); } } else if (allowedArr.length) { if (ctx.method === 'OPTIONS') { // 如果是OPTIONS请求,则认为是请求成功,响应200,并根据OPTIONS请求约定返回允许的http方法 ctx.status = 200; ctx.body = ''; ctx.set('Allow', allowedArr.join(', ')); } else if (!allowed[ctx.method]) { // 如果请求方法在router实例的methods中存在,但是在匹配的路由中该http方法不存在 if (options.throw) { var notAllowedThrowable; if (typeof options.methodNotAllowed === 'function') { notAllowedThrowable = options.methodNotAllowed(); // set whatever the user returns from their function } else { notAllowedThrowable = new HttpError.MethodNotAllowed(); } throw notAllowedThrowable; } else { // 响应405 http请求方法错误 ctx.status = 405; ctx.set('Allow', allowedArr.join(', ')); } } } } }); }; };

Router.prototype.use

/** * Use given middleware. * * Middleware run in the order they are defined by `.use()`. They are invoked * sequentially, requests start at the first middleware and work their way * "down" the middleware stack. * * @example * * ```javascript * // session middleware will run before authorize * router * .use(session()) * .use(authorize()); * * // use middleware only with given path * router.use('/users', userAuth()); * * // or with an array of paths * router.use(['/users', '/admin'], userAuth()); * * app.use(router.routes()); * ``` * * @param {String=} path * @param {Function} middleware * @param {Function=} ... * @returns {Router} */ Router.prototype.use = function () { var router = this; var middleware = Array.prototype.slice.call(arguments); var path; // support array of paths // 如果第一个参数是一个数组,且数组中元素为字符串 if (Array.isArray(middleware[0]) && typeof middleware[0][0] === 'string') { // 递归调用use方法 middleware[0].forEach(function (p) { router.use.apply(router, [p].concat(middleware.slice(1))); }); return this; } var hasPath = typeof middleware[0] === 'string'; if (hasPath) { path = middleware.shift(); } middleware.forEach(function (m) { // 如果这个中间件是由router.routes()方法返回的dispatch中间件,即这是一个嵌套的路由 if (m.router) { // 遍历router.stack属性中所有的layer m.router.stack.forEach(function (nestedLayer) { // 被嵌套的路由需要以父路由path为前缀 if (path) nestedLayer.setPrefix(path); // 如果父路由有指定前缀,被嵌套的路由需要把这个前缀再加上 if (router.opts.prefix) nestedLayer.setPrefix(router.opts.prefix); router.stack.push(nestedLayer); }); if (router.params) { Object.keys(router.params).forEach(function (key) { m.router.param(key, router.params[key]); }); } } else { router.register(path || '(.*)', [], m, { end: false, ignoreCaptures: !hasPath }); } }); return this; };

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/1690e3f2cd69f10ca1d18c4f9e7fcd5f.html