Node.js / Express.js - Как работает app.router?

298

Прежде чем спросить об этом, app.routerя должен объяснить, по крайней мере, что, по моему мнению, происходит при работе с промежуточным программным обеспечением. Чтобы использовать промежуточное ПО, нужно использовать функцию app.use(). Когда промежуточное программное обеспечение выполняется, оно будет вызывать следующее промежуточное программное обеспечение с помощью next()или делать так, чтобы промежуточное программное обеспечение больше не вызывалось. Это означает, что порядок, в котором я размещаю свои вызовы промежуточного программного обеспечения, важен, потому что некоторое промежуточное программное обеспечение зависит от другого промежуточного программного обеспечения, а некоторое промежуточное программное обеспечение ближе к концу может даже не вызываться.

Сегодня я работал над своим приложением, и мой сервер работал в фоновом режиме. Я хотел внести некоторые изменения, обновить страницу и сразу же увидеть изменения. В частности, я вносил изменения в свой макет. Я не смог заставить его работать, поэтому я искал Stack Overflow для ответа и нашел этот вопрос . Он говорит, чтобы убедиться, что express.static()это ниже require('stylus'). Но когда я смотрел на код этого OP, я увидел, что его app.routerзвонок был в самом конце его вызовов промежуточного программного обеспечения, и я попытался выяснить, почему это было.

Когда я сделал свое заявление Express.js (версия 3.0.0rc4), я использовал команду express app --sessions --css stylusи подать мой app.js код пришел настройки с моим app.routerвыше как express.static()и require('stylus')звонками. Таким образом, кажется, что если он уже настроен таким образом, он должен оставаться таким.

После реорганизации моего кода, чтобы я мог видеть изменения моего Стилуса, это выглядит так:

app.configure(function(){
  //app.set() calls
  //app.use() calls
  //...
  app.use(app.router);
  app.use(require('stylus').middleware(__dirname + '/public'));
  app.use(express.static(__dirname + '/public', {maxAge: 31557600000}));
});

app.get('/', routes.index);

app.get('/test', function(req, res){
  res.send('Test');
});

Поэтому я решил, что первым шагом будет выяснить, почему это важно даже app.routerв моем коде. Поэтому я прокомментировал это, запустил свое приложение и перешел к /. Он показал мою страницу индекса просто отлично. Хм, может быть, это сработало, потому что я экспортировал маршрутизацию из моего файла маршрутов (rout.index). Затем я перешел к /testпункту «Тест» на экране. Хаха, хорошо, я понятия не имею, что app.routerделает. Включено ли это в мой код или нет, моя маршрутизация в порядке. Так что я определенно что-то упускаю.

Вот мой вопрос:

Может кто-нибудь объяснить, что app.routerделает, важность этого и где я должен поместить это в мои вызовы промежуточного программного обеспечения? Было бы также хорошо, если бы я получил краткое объяснение express.static(). Насколько я могу судить, express.static()это кэш моей информации, и если приложение не может найти запрошенную страницу, оно проверит кеш, чтобы узнать, существует ли оно.

Aust
источник
18
Спасибо, что задали этот вопрос. Я гуглил вокруг, чтобы найти этот ответ (и вопрос, чтобы побудить его).
Хари Селдон
8
Это был действительно хорошо написанный вопрос, я гуглял то же самое.
Кирн

Ответы:

329

Примечание. Здесь описывается, как Express работал в версиях 2 и 3. Информацию о Express 4 см. В конце этого поста.


staticпросто обслуживает файлы ( статические ресурсы) с диска. Вы даете ему путь (иногда называемый точкой монтирования), и он обслуживает файлы в этой папке.

Например, express.static('/var/www')будет обслуживать файлы в этой папке. Таким образом, запрос на ваш сервер Node http://server/file.htmlбудет обслуживать /var/www/file.html.

routerэто код, который запускает ваши маршруты. Когда вы это делаете app.get('/user', function(req, res) { ... });, это именно то, routerчто на самом деле вызывает функцию обратного вызова для обработки запроса.

Порядок передачи вещей app.useопределяет порядок, в котором каждому промежуточному ПО предоставляется возможность обрабатывать запрос. Например, если у вас есть файл с именем test.htmlв вашей статической папке и маршрут:

app.get('/test.html', function(req, res) {
    res.send('Hello from route handler');
});

Какой из них отправляется клиенту с запросом http://server/test.html? Какое бы промежуточное программное обеспечение было предоставлено useпервым.

Если вы делаете это:

app.use(express.static(__dirname + '/public'));
app.use(app.router);

Затем файл на диске подается.

Если вы делаете это по-другому,

app.use(app.router);
app.use(express.static(__dirname + '/public'));

Затем обработчик маршрута получает запрос, и «Привет из обработчика маршрута» отправляется в браузер.

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

Обратите внимание , что если вы явно не , он неявно добавляется курьерским в точке вы определяете маршрут (который почему ваши маршруты все еще работали , даже если вы закомментировать ).userouterapp.use(app.router)


Комментатор был воспитан еще один пункт о порядке staticи routerчто я не имел имя: влияние на общую производительность вашего приложения.

Еще одна причина use routerвыше static- оптимизировать производительность. Если поставить staticпервым, то при каждом запросе вы будете нажимать на жесткий диск, чтобы увидеть, существует ли файл. В быстром тесте я обнаружил, что на незагруженном сервере эти издержки составили ~ 1 мс. (Скорее всего, это число будет выше при загрузке, когда запросы будут конкурировать за доступ к диску.)

Во- routerпервых, запрос, соответствующий маршруту, никогда не должен попадать на диск, экономя драгоценные миллисекунды.

Конечно, есть способы уменьшить staticнакладные расходы.

Лучший вариант - поместить все ваши статические ресурсы в определенную папку. (IE /static) Затем вы можете подключиться staticк этому пути, чтобы он работал только тогда, когда путь начинается с /static:

app.use('/static', express.static(__dirname + '/static'));

В этой ситуации вы бы поставили это выше router. Это позволяет избежать обработки другого промежуточного программного обеспечения / маршрутизатора, если файл присутствует, но, честно говоря, я сомневаюсь, что вы получите так много.

Вы также можете использовать staticCache, который кэширует статические ресурсы в памяти, так что вам не нужно нажимать на диск для часто запрашиваемых файлов. ( Предупреждение: staticCache очевидно, будет удалено в будущем.)

Тем не менее, я не думаю, что staticCacheкэширует отрицательные ответы (когда файл не существует), поэтому не поможет, если вы поставили staticCacheвыше, routerне подключив его к пути.

Как и в случае со всеми вопросами о производительности, измерьте и сравните свое реальное приложение (под нагрузкой), чтобы увидеть, где на самом деле существуют узкие места.


Экспресс 4

Экспресс 4.0 удаляет app.router . Все middleware ( app.use) и маршруты ( app.getи др.) Теперь обрабатываются именно в том порядке, в котором они были добавлены.

Другими словами:

Все методы маршрутизации будут добавлены в порядке их появления. Вы не должны делать app.use(app.router). Это устраняет наиболее распространенную проблему с Express.

Другими словами, микширование app.use()и app[VERB]()будет работать именно в том порядке, в котором они называются.

app.get('/', home);
app.use('/public', require('st')(process.cwd()));
app.get('/users', users.list);
app.post('/users', users.create);

Узнайте больше об изменениях в Express 4.

josh3736
источник
2
The routerидет в одном месте. Если в первый раз вы называете app.get(или postили другие), вы еще не used app.router, Экспресс добавляет это для вас.
josh3736
4
@MikeCauser: Нет, потому что накладные расходы на доступ к диску (чтобы увидеть, существует ли файл) больше, чем накладные расходы на вызов функции. В моем тесте эта нагрузка составила 1 мс на незагруженном сервере. Скорее всего, это будет выше под нагрузкой, когда запросы будут конкурировать за доступ к диску. С staticAFTER router, вопрос о другом промежуточном слое становится неуместным , поскольку она должна быть выше маршрутизатора.
josh3736
2
Замечательное объяснение! Спасибо вам большое!
Кирн
3
app.routerбудет удален в текущей основной ветви, который будет экспресс-4.0 . Каждый маршрут становится отдельным промежуточным ПО.
yanychar
3
Еще одно уточнение, как я работаю с этим. В экспрессе 4 маршрутизатору можно назначить несколько маршрутов, и затем для использования маршрутизатора маршрутизатору дается корневой путь и он помещается в стек «промежуточного программного обеспечения» через app.use (путь, маршрутизатор). Это позволяет связанным маршрутам использовать каждый собственный маршрутизатор и назначать базовый путь как единое целое. Если бы я понял это лучше, я бы предложил опубликовать другой ответ. Опять же, я получаю это от scotch.io/tutorials/javascript/…
Джо Лапп
2

Маршрутизация означает определение того, как приложение отвечает на запрос клиента к конкретной конечной точке, которая является URI (или путем) и конкретным методом HTTP-запроса (GET, POST и т. Д.). Каждый маршрут может иметь одну или несколько функций-обработчиков, которые выполняются при сопоставлении маршрута.

В Express 4.0 Router нам дается больше гибкости, чем когда-либо прежде в определении наших маршрутов.

express.Router () используется несколько раз для определения групп маршрутов.

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

В качестве промежуточного программного обеспечения используется маршрут для проверки параметров с помощью «.param ()».

app.route () используется в качестве ярлыка для маршрутизатора для определения нескольких запросов на маршруте

когда мы используем app.route (), мы присоединяем наше приложение к этому маршрутизатору.

var express = require('express'); //used as middleware
var app = express(); //instance of express.
app.use(app.router);
app.use(express.static(__dirname + '/public')); //All Static like [css,js,images] files are coming from public folder
app.set('views',__dirname + '/views'); //To set Views
app.set('view engine', 'ejs'); //sets View-Engine as ejs
app.engine('html', require('ejs').renderFile); //actually rendering HTML files through EJS. 
app.get('/', function (req, res) {
  res.render('index');  
})
app.get('/test', function (req, res) {
  res.send('test')
})
Парт Равал
источник
0

В экспресс-версии 4 мы можем легко определить маршруты следующим образом:

server.js:

const express = require('express');
const app = express();
const route = require('./route');

app.use('/route', route);
// here we pass in the imported route object

app.listen(3000, () => console.log('Example app listening on port 3000!'));

route.js:

const express = require('express');
const router = express.Router();

router.get('/specialRoute', function (req, res, next) {
     // route is now http://localhost:3000/route/specialRoute
});

router.get('/', function (req, res, next) {
    // route is now http://localhost:3000/route
});

module.exports = router;

В server.jsмы импортировали объект маршрутизатора из route.jsфайла и применять его следующим образом в server.js:

app.use('/route', route);

Теперь все маршруты route.jsимеют следующий базовый URL:

HTTP: // локальный: 3000 / маршрута

Почему этот подход:

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

Виллем ван дер Веен
источник