123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- 'use strict';
- const join = require('path').join;
- const is = require('is-type-of');
- const inspect = require('util').inspect;
- const assert = require('assert');
- const debug = require('debug')('egg-core:middleware');
- const pathMatching = require('egg-path-matching');
- const utils = require('../../utils');
- module.exports = {
- /**
- * Load app/middleware
- *
- * app.config.xx is the options of the middleware xx that has same name as config
- *
- * @function EggLoader#loadMiddleware
- * @param {Object} opt - LoaderOptions
- * @example
- * ```js
- * // app/middleware/status.js
- * module.exports = function(options, app) {
- * // options == app.config.status
- * return function*(next) {
- * yield next;
- * }
- * }
- * ```
- * @since 1.0.0
- */
- loadMiddleware(opt) {
- this.timing.start('Load Middleware');
- const app = this.app;
- // load middleware to app.middleware
- opt = Object.assign({
- call: false,
- override: true,
- caseStyle: 'lower',
- directory: this.getLoadUnits().map(unit => join(unit.path, 'app/middleware')),
- }, opt);
- const middlewarePaths = opt.directory;
- this.loadToApp(middlewarePaths, 'middlewares', opt);
- for (const name in app.middlewares) {
- Object.defineProperty(app.middleware, name, {
- get() {
- return app.middlewares[name];
- },
- enumerable: false,
- configurable: false,
- });
- }
- this.options.logger.info('Use coreMiddleware order: %j', this.config.coreMiddleware);
- this.options.logger.info('Use appMiddleware order: %j', this.config.appMiddleware);
- // use middleware ordered by app.config.coreMiddleware and app.config.appMiddleware
- const middlewareNames = this.config.coreMiddleware.concat(this.config.appMiddleware);
- debug('middlewareNames: %j', middlewareNames);
- const middlewaresMap = new Map();
- for (const name of middlewareNames) {
- if (!app.middlewares[name]) {
- throw new TypeError(`Middleware ${name} not found`);
- }
- if (middlewaresMap.has(name)) {
- throw new TypeError(`Middleware ${name} redefined`);
- }
- middlewaresMap.set(name, true);
- const options = this.config[name] || {};
- let mw = app.middlewares[name];
- mw = mw(options, app);
- assert(is.function(mw), `Middleware ${name} must be a function, but actual is ${inspect(mw)}`);
- mw._name = name;
- // middlewares support options.enable, options.ignore and options.match
- mw = wrapMiddleware(mw, options);
- if (mw) {
- if (debug.enabled) {
- // show mw debug log on every request
- mw = debugWrapper(mw);
- }
- app.use(mw);
- debug('Use middleware: %s with options: %j', name, options);
- this.options.logger.info('[egg:loader] Use middleware: %s', name);
- } else {
- this.options.logger.info('[egg:loader] Disable middleware: %s', name);
- }
- }
- this.options.logger.info('[egg:loader] Loaded middleware from %j', middlewarePaths);
- this.timing.end('Load Middleware');
- },
- };
- function wrapMiddleware(mw, options) {
- // support options.enable
- if (options.enable === false) return null;
- // support generator function
- mw = utils.middleware(mw);
- // support options.match and options.ignore
- if (!options.match && !options.ignore) return mw;
- const match = pathMatching(options);
- const fn = (ctx, next) => {
- if (!match(ctx)) return next();
- return mw(ctx, next);
- };
- fn._name = mw._name + 'middlewareWrapper';
- return fn;
- }
- function debugWrapper(mw) {
- const fn = (ctx, next) => {
- debug('[%s %s] enter middleware: %s', ctx.method, ctx.url, mw._name);
- return mw(ctx, next);
- };
- fn._name = mw._name + 'DebugWrapper';
- return fn;
- }
|