Экспресс-анализ исходного кода

задняя часть сервер JavaScript Express

Обзор

Простейший пример сервера, предоставленный NODEJS, заключается в следующем:

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World!\n');
});

Фреймворк Express не такой уж и волшебный, это просто проксиhttp.createServer(requestHandler)обработчик запросов в . И используйте зарегистрированное промежуточное ПО и сопоставление маршрутов для ответа на входящие запросы пользователей.

вся идея

Читая исходный код, думаю, логику Express можно разделить на две части: запуск службы и ответ на запрос.

Начать этап обслуживанияОтноситсяhttp.createServer(requestHandler)иserver.listener()Ряд действий по инициализации, выполняемых перед вызовом двух API.

Стадия ответа на запросОтносится к обработчику события запроса, которое срабатывает, когда сервер получает запрос от клиента.

Начать этап обслуживания

Наиболее важной частью запуска службы является регистрация промежуточного программного обеспечения и маршрутов.

Можно сказать, что промежуточное ПО и маршрутизация — это функции, которые есть почти на всех серверах. В среде Express ПО промежуточного слоя и маршрутизация абстрагируются в объекты уровня.В этой статье контейнер, в котором хранятся объекты уровня ПО промежуточного слоя, называетсяобъект маршрутизатора промежуточного программного обеспечения, контейнер, в котором хранится объект слоя маршрутизации, называетсяобъект маршрутизатора маршрута.

В среде Express промежуточное ПО — это обратный вызов, который будет выполняться при совпадении пути, и маршрут должен соответствовать не только пути, но и методу http (например, get, post и т. д.). Таким образом, дляобъект маршрутизатора промежуточного программного обеспечения, обратный вызов будет выполнен сразу после сопоставления пути, нообъект маршрутизатора маршрутаОбратный вызов выполнен после согласования пути объединения какrouter.handle(req, res, next)логика внутри будет по-прежнему соответствовать методу http.

1. app.useметод

зарегистрирован лиобъект маршрутизатора промежуточного программного обеспечениявсе ещеобъект маршрутизатора маршрутамы все будем использоватьapp.use.

app.useМетод, по сути, вызывает метод использования своего собственного объекта-маршрутизатора:

var router = this._router;

fns.forEach(function (fn) {
// non-express app
if (!fn || !fn.handle || !fn.set) {
    return router.use(path, fn);
}

debug('.use app under %s', path);
fn.mountpath = path;
fn.parent = this;

// restore .app property on req and res
router.use(path, function mounted_app(req, res, next) {
    var orig = req.app;
    fn.handle(req, res, function (err) {
    setPrototypeOf(req, orig.request)
    setPrototypeOf(res, orig.response)
    next(err);
    });
});

// mounted an app
fn.emit('mount', this);
}, this);

2. Объект маршрутизатора промежуточного программного обеспечения

Когда мы вызываем что-то вродеapp.use('/', fn)Такой оператор фактически является промежуточным программным обеспечением регистрации.

Здесь необходимо объяснить, что каждое экспресс-приложение будет использоваться при его инициализации.app.lazyrouter()Чтобы создать экземпляр объекта маршрутизатора, в этой статье мы будем называть его объектом маршрутизатора промежуточного программного обеспечения, поскольку он в основном отвечает за хранение объекта уровня промежуточного программного обеспечения, но он также может регистрировать объект маршрутизатора.Например, в процессе разработки мы будем называть форма какapp.use('/test', testRouter)Заявление.

Объект маршрутизатора промежуточного программного обеспечения поддерживает этот массив стека, который используется для загрузки объекта Layer.

Когда вызывается метод использования объекта маршрутизатора, путь и обратный вызов инкапсулируются в объект Layer и помещаются в массив стека.

Обратите внимание: маршрут объекта уровня объекта маршрутизатора промежуточного программного обеспечения не определен, что отличается от маршрута объекта уровня объекта маршрутизатора.

var layer = new Layer(path, {
    sensitive: this.caseSensitive,
    strict: false,
    end: false
}, fn);

layer.route = undefined;

this.stack.push(layer);

3. Объект маршрутизатора маршрута

Когда мы вызываем что-то вродеapp.use('/test', testRouter)Заявление может быть выражено как регистрация промежуточного программного обеспечения маршрутизации, и это промежуточное программное обеспечение выглядит следующим образом:routerфункция:

function router(req, res, next) {
  router.handle(req, res, next);
}

Чтобы отличить его от объекта маршрутизатора промежуточного программного обеспечения, в этой статье промежуточное программное обеспечение маршрутизации, зарегистрированное в объекте маршрутизатора промежуточного программного обеспечения, определяется как объект маршрутизатора маршрутизации.

На данный момент я больше всего хочу вам сказать, что в экспрессе объекты маршрутизатора могут быть вложены таким образом.

Как упоминалось ранее, маршрут также будет абстрагироваться в объект уровня, аrouterФункция передается в качестве третьего параметра конструктора Layer.

4. Метод метода HTTP и экземпляр маршрута

HTTP-метод относится к методам HTTP-запроса, таким как получение, отправка, размещение, удаление и заголовок.

объект маршрутизатора маршрутаНеобходимо не только совпадать с путем, но также совпадать с методом HTTP. Функция, отвечающая за сопоставление HTTP-метода, выполняется экземпляром Route.

когда мы звонимapp[method]илиrouter[method]при звонкеrouter.routeметод (следующийthis.route(path)),следующее:

// create Router#VERB functions
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;
  };
});

router.routeМетод создаст новый объект слоя и установит обратный вызов наroute.dispatch.bind(route), что согласуется с вышеупомянутымобъект маршрутизатора промежуточного программного обеспеченияОтличается, и маршрут слоя больше не является неопределенным и, наконец, возвращает новый экземпляр маршрута. код показывает, как показано ниже:

proto.route = function route(path) {
  var route = new Route(path);

  var layer = new Layer(path, {
    sensitive: this.caseSensitive,
    strict: this.strict,
    end: true
  }, route.dispatch.bind(route));

  layer.route = route;

  this.stack.push(layer);
  return route;
};

Итак, какова роль возвращенного экземпляра Route? Сначала взгляните на его конструктор:

function Route(path) {
  this.path = path;
  this.stack = [];

  debug('new %o', path)

  // route handlers for various http methods
  this.methods = {};
}

Экземпляр Route поддерживает массив стека, который используется для сбора объектов Layer; он также поддерживает этот объект методов, который используется для указания методов http, которым может соответствовать объект маршрута.

Объект Layer, собранный маршрутом, поддерживает реальный обратный вызов маршрута, который является следующим дескриптором:

var layer = Layer('/', {}, handle);
layer.method = method;

this.methods[method] = true;
this.stack.push(layer);

5. Слой объекта

Объект Layer поддерживает этот путь и обратный вызов, который упорядочивает путь для использования вСтадия ответа на запросЧтобы сопоставить путь, сначала посмотрите на его конструктор:

function Layer(path, options, fn) {
  if (!(this instanceof Layer)) {
    return new Layer(path, options, fn);
  }

  debug('new %o', path)
  var opts = options || {};

  this.handle = fn;
  this.name = fn.name || '<anonymous>';
  this.params = undefined;
  this.path = undefined;
  this.regexp = pathRegexp(path, this.keys = [], opts);

  // set fast path flags
  this.regexp.fast_star = path === '*'
  this.regexp.fast_slash = path === '/' && opts.end === false
}

Существует три типа объектов слоя:

Категория слоя route method
Уровень промежуточного программного обеспечения undefined undefined
Слой маршрутизации не неопределенный undefined
route Layer undefined не неопределенный

Обратный вызов экземпляра слоя промежуточного слоя — fn, зарегистрированная функция промежуточного слоя; обратный вызов экземпляра уровня маршрутизации —function router(req, res, next);Все обратные вызовы экземпляра слоя маршрутаroute.dispatch.bind(route).

Стадия ответа на запрос

Начав этап обслуживания, мы завершили подготовку сервера — регистрацию промежуточного ПО и маршрутизацию.

Когда приложение выполняется дляserver.listener(), вы можете начать принимать и обрабатывать запрос клиента и, наконец, вернуть ответ сервера.

1. Улучшить объект req и объект res

Когда приходит запрос, NodeJS абстрагирует запрос в req (экземпляр http.IncomingMessage), абстрагирует ответ в res (экземпляр http.ServerResponse) и передает обработчику события запроса сервера, но в среде Express. , Объект req и объект res были улучшены.

Для расширенного содержимого обратитесь к request.js и response.js в том же каталоге, что и express.js.

Так как же он усиливается?

существуетapp.lazyrouterВ методе было добавлено промежуточное программное обеспечение, которое выглядит следующим образомmiddleware.init(this)

app.lazyrouter = function lazyrouter() {
  if (!this._router) {
    this._router = new Router({
      caseSensitive: this.enabled('case sensitive routing'),
      strict: this.enabled('strict routing')
    });

    this._router.use(query(this.get('query parser fn')));
    this._router.use(middleware.init(this));
  }
};

пока вmiddleware.init(this), вы можете видеть, что прототип req и res сбрасывается:

exports.init = function(app){
  return function expressInit(req, res, next){
    if (app.enabled('x-powered-by')) res.setHeader('X-Powered-By', 'Express');
    req.res = res;
    res.req = req;
    req.next = next;

    setPrototypeOf(req, app.request)
    setPrototypeOf(res, app.response)

    res.locals = res.locals || Object.create(null);

    next();
  };
};

2. ПО промежуточного слоя и маршруты для сопоставления регулярных выражений

Поскольку мы зарегистрировали промежуточное ПО и маршрутизацию на этапе запуска службы и абстрагировали их в объекты уровня, при обработке фазы запроса все становится ясно.

Основная логика такова: Пройдите через контейнер стека, поддерживаемый маршрутизатором; Для уровня промежуточного ПО (т. е. layer.route не определен) функция промежуточного ПО может быть выполнена после успешного сопоставления пути; Для уровня маршрутизации (т. е. layer.route не является неопределенным) после успешного сопоставления пути необходимо сопоставить метод http для выполнения функции маршрутизации.

В этом процессе есть следующие важные методы:

app.handle, запись экспресс-приложения для обработки запросов, по существу вызывает дескриптор собственного маршрутизатора. router.handle, пройдите массив стека, поддерживаемый маршрутизатором, чтобы найти объект уровня, который соответствует пути Route.prototype._handles_method, для объекта уровня маршрута этот метод также требуется для проверки, может ли он соответствовать методу http Route.prototype.dispatch, пройдите массив стека, поддерживаемый маршрутом, и найдите объект слоя, который соответствует пути и методу http. Layer.prototype.match, ключ к сопоставлению путей Layer.prototype.handle_request, выполнить обратный вызов после успешного совпадения

3. Механизм шаблонов

Механизм шаблонов не является оригинальным автором экспресса, но вводит другие сторонние библиотеки, а затем использует API, предоставленный сторонней библиотекой, для отображения страницы ответа и возврата ее клиенту.

В настоящее время поддерживается болееejsиpugОба шаблонизатора.

Экспресс-мозаика

Приложение Express может быть смонтировано в другом приложении Express, потому что, по сути, приложение Express должно поддерживать свой собственный объект маршрутизатора, поэтому способ монтирования фактически заключается в регистрации промежуточного программного обеспечения в родительском экспресс-приложении, промежуточного программного обеспечения. Компонент отвечает за передачу req и res в дочернее экспресс-приложение и позволяет им установить отношения родитель-потомок.Исходный код выглядит следующим образом:

// restore .app property on req and res
router.use(path, function mounted_app(req, res, next) {
    var orig = req.app;
    fn.handle(req, res, function (err) {
    setPrototypeOf(req, orig.request)
    setPrototypeOf(res, orig.response)
    next(err);
    });
});

Ссылаться на

Экспресс источник@4.16.3 Экспресс китайская документация