schangxiang@126.com
2025-09-19 0821aa23eabe557c0d9ef5dbe6989c68be35d1fe
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
'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
   *
   * @method 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;
}