Обзор
Простейший пример сервера, предоставленный 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);
});
});