Node.js / Express.js - Як працює app.router?


298

Перш ніж запитати про app.routerмене, я думаю, що мені слід пояснити принаймні те, що, на мою думку, відбувається під час роботи з середнім програмним забезпеченням. Для використання середнього програмного забезпечення використовується функція app.use(). Коли програмне забезпечення середнього програмного забезпечення виконується, воно або зателефонує до наступного середнього програмного забезпечення за допомогою, next()або зробить його таким чином, щоб більше не викликали середнє програмне забезпечення. Це означає, що порядок, в якому я розміщую свої посередницькі дзвінки, є важливим, оскільки деяке проміжне програмне забезпечення залежить від іншого проміжного програмного забезпечення, а якесь середнє програмне забезпечення в кінці може навіть не називатися.

Сьогодні я працював над моєю програмою, і мій сервер працював у фоновому режимі. Я хотів внести деякі зміни та оновити свою сторінку і побачити зміни негайно. Зокрема, я вносив зміни до свого макета. Я не зміг змусити його працювати, тому я шукав відповідь на переповнення стека і знайшов це запитання . Це говорить, щоб переконатися, що express.static()це внизу require('stylus'). Але коли я дивився на код цього ОП, то побачив, що він app.routerдзвонив в самому кінці викликів середнього програмного забезпечення, і я спробував з’ясувати, чому це було.

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

Після перестановки коду, щоб я міг побачити зміни мого 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свій код. Тому я прокоментував це, запустив додаток і перейшов до /. Він відображав мою індексну сторінку просто чудово. Гм, можливо, це спрацювало, тому що я експортував маршрутизацію з мого файлу маршрутів (route.index). Тож далі я перейшов, /testі він відобразив Тест на екрані. Ха-ха, гаразд, я поняття не маю, що app.routerробить. Незалежно від того, включений він у мій код чи ні, моє маршрутизація чудово. Тож мені певно чогось не вистачає.

Тож ось моє запитання:

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


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'));

Потім обробник маршруту отримує запит, і "Привіт від обробника маршруту" надсилається до браузера.

Зазвичай ви хочете поставити маршрутизатор над статичним посередництвом, щоб випадково названий файл не міг перекрити один із ваших маршрутів.

Зауважте, що якщо ви явно не зробите useце router, це імпліцитно додається Express в точці, яку ви визначаєте, маршрут (саме тому ваші маршрути все ще працювали, навіть якщо ви коментували app.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 . Всі проміжне програмне забезпечення ( 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.


2
routerЙде в одному місці. Якщо в перший раз ви називаєте app.get(або postчи інші), ви ще не used app.router, Експрес додає це для вас.
josh3736

4
@MikeCauser: Ні, оскільки накладні витрати на доступ до диска (щоб побачити, чи існує файл чи більше) більше, ніж накладні виклики функції. У моєму тесті , цей накладний обсяг становив 1 мс на не завантаженому сервері. Це, швидше за все, буде вище при навантаженні, де запити змагатимуться за доступ до диска. З staticAFTER router, питання про інше проміжному шарі стає недоречним , оскільки вона повинна бути вище маршрутизатора.
josh3736

2
Чудове пояснення! Дуже дякую!
Кірн

3
app.routerбуде видалений в поточної основної гілки, який буде експрес-4.0 . Кожен маршрут стає окремим проміжним програмним забезпеченням.
яничар

3
Ще одне уточнення, оскільки я працюю з цим. У експресі 4 до маршрутизатора можуть бути призначені кілька маршрутів, а потім для використання маршрутизатора маршрутизатору надається кореневий шлях і розміщений у стеці "середнє програмне забезпечення" через app.use (шлях, маршрутизатор). Це дозволяє пов'язаним маршрутам для кожного використовувати власний маршрутизатор і призначати базовий шлях як одиницю. Якби я зрозумів це краще, пропоную ще одну відповідь. Знову я отримую це від scotch.io/tutorials/javascript/…
Джо Лапп,

2

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

У маршрутизаторі Express 4.0 ми надаємо більшу гнучкість, ніж будь-коли раніше, у визначенні наших маршрутів.

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

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

route використовується як проміжне програмне забезпечення для перевірки параметрів за допомогою ".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: // localhost: 3000 / маршрут

Чому такий підхід:

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.