Node.js / Express.js - Jak działa app.router?

298

Zanim zapytam o app.router, myślę, że powinienem przynajmniej wyjaśnić, co myślę, co dzieje się podczas pracy z oprogramowaniem pośrednim. Aby użyć oprogramowania pośredniego, należy użyć tej funkcji app.use(). Podczas wykonywania oprogramowania pośredniego wywoła następne oprogramowanie pośrednie za pomocą next()lub sprawi, że nie będzie już wywoływane. Oznacza to, że kolejność, w jakiej umieszczam wywołania oprogramowania pośredniego, jest ważna, ponieważ niektóre oprogramowanie pośrednie zależy od innego oprogramowania pośredniego, a niektóre oprogramowanie pośrednie pod koniec może nawet nie zostać wywołane.

Dzisiaj pracowałem nad aplikacją i mój serwer działał w tle. Chciałem wprowadzić pewne zmiany, odświeżyć stronę i od razu je zobaczyć. W szczególności wprowadzałem zmiany w moim układzie. Nie mogłem go uruchomić, więc szukałem odpowiedzi na Przepełnienie stosu i znalazłem to pytanie . Mówi, aby upewnić się, że express.static()jest poniżej require('stylus'). Ale kiedy patrzyłem na kod tego OP, zobaczyłem, że miał swoje app.routerpołączenie na samym końcu swoich wywołań oprogramowania pośredniego i próbowałem dowiedzieć się, dlaczego tak się dzieje.

Kiedy utworzyłem aplikację Express.js (wersja 3.0.0rc4), użyłem polecenia, express app --sessions --css stylusaw moim pliku app.js kod został dostarczony wraz z moimi app.routerpowyższymi wywołaniami express.static()i require('stylus'). Wygląda więc na to, że jeśli tak już jest, to tak powinno pozostać.

Po zmianie aranżacji kodu, aby zobaczyć zmiany w rysiku, wygląda to tak:

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

Zdecydowałem więc, że pierwszym krokiem będzie ustalenie, dlaczego tak ważne jest, aby mieć nawet app.routermój kod. Skomentowałem to, uruchomiłem aplikację i nawigowałem do /. Moja strona indeksu wyświetlała się dobrze. Hmm, może zadziałało, ponieważ eksportowałem routing z mojego pliku tras (route.index). Następnie nawigowałem /testi wyświetliłem Test na ekranie. Haha, OK, nie mam pojęcia co app.routerrobi. Niezależnie od tego, czy jest to zawarte w moim kodzie, czy nie, moje routing jest w porządku. Więc zdecydowanie czegoś mi brakuje.

Oto moje pytanie:

Czy ktoś mógłby wyjaśnić, co to app.routerznaczy, jak ważne jest to miejsce i gdzie powinienem to umieścić w wywołaniach oprogramowania pośredniego? Byłoby również miło, gdybym otrzymał krótkie wyjaśnienie na temat express.static(). O ile mogę stwierdzić, express.static()jest to pamięć podręczna moich informacji, a jeśli aplikacja nie może znaleźć żądanej strony, sprawdzi pamięć podręczną, aby sprawdzić, czy istnieje.

Aust
źródło
18
Dziękuję za pytanie. Googlowałem się wokoło, by znaleźć tę odpowiedź (i pytanie, by ją podpowiedzieć).
Hari Seldon,
8
To było naprawdę dobrze napisane pytanie, przeglądałem to samo.
Kirn

Odpowiedzi:

329

Uwaga: opisuje, jak Express działał w wersjach 2 i 3. Informacje na temat Express 4 można znaleźć na końcu tego postu.


staticpo prostu podaje pliki ( zasoby statyczne ) z dysku. Dajesz mu ścieżkę (czasami nazywaną punktem montowania) i służy ona do plików w tym folderze.

Na przykład express.static('/var/www')wyświetlałby pliki w tym folderze. Tak więc żądanie do twojego serwera Node http://server/file.htmlbyłoby spełnione /var/www/file.html.

routerto kod, który obsługuje twoje trasy. Kiedy to zrobisz app.get('/user', function(req, res) { ... });, to routerfaktycznie wywołuje funkcję wywołania zwrotnego w celu przetworzenia żądania.

Kolejność przekazywania rzeczy app.useokreśla kolejność, w jakiej każde oprogramowanie pośrednie ma możliwość przetworzenia żądania. Na przykład jeśli masz plik o nazwie test.htmlw folderze statycznym i trasę:

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

Który zostaje wysłany do klienta z prośbą http://server/test.html? Które oprogramowanie pośrednie zostanie podane jako usepierwsze.

Jeśli to zrobisz:

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

Następnie plik na dysku jest obsługiwany.

Jeśli zrobisz to w inny sposób,

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

Następnie procedura obsługi trasy otrzymuje żądanie, a „Witaj z funkcji obsługi trasy” jest wysyłane do przeglądarki.

Zwykle chcesz umieścić router nad statycznym oprogramowaniem pośrednim, aby przypadkowo nazwany plik nie mógł przesłonić jednej z twoich tras.

Należy pamiętać, że jeśli nie jawnie , to jest domyślnie dodany przez Express, w momencie zdefiniowania trasy (dlatego wasze drogi nadal pracował, nawet jeśli wykomentowane ).userouterapp.use(app.router)


Komentator podniósł kolejną kwestię dotyczącą kolejności statici do routerktórej nie odniosłem się: wpływ na ogólną wydajność Twojej aplikacji.

Kolejnym powodem do use routerpowyższego staticjest optymalizacja wydajności. Jeśli umieścisz na staticpierwszym miejscu, uderzysz w dysk twardy przy każdym pojedynczym żądaniu, aby sprawdzić, czy plik istnieje. W szybkim teście stwierdziłem, że narzut ten wyniósł ~ 1ms na nieobciążonym serwerze. (Liczba ta prawdopodobnie będzie wyższa pod obciążeniem, gdy żądania będą konkurować o dostęp do dysku).

Po routerpierwsze żądanie pasujące do trasy nigdy nie musi trafić na dysk, co oszczędza cenne milisekundy.

Oczywiście istnieją sposoby na zmniejszenie statickosztów ogólnych.

Najlepszą opcją jest umieszczenie wszystkich zasobów statycznych w określonym folderze. (IE /static) Następnie możesz zamontować staticna tej ścieżce, aby działała tylko wtedy, gdy ścieżka zaczyna się od /static:

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

W tej sytuacji postawisz to powyżej router. Pozwala to uniknąć przetwarzania innego oprogramowania pośredniego / routera, jeśli plik jest obecny, ale szczerze mówiąc, wątpię, czy zyskasz tyle.

Możesz również użyć staticCache, który buforuje zasoby statyczne w pamięci, abyś nie musiał uderzać w dysk w poszukiwaniu często żądanych plików. ( Ostrzeżenie: staticCache prawdopodobnie zostaną usunięte w przyszłości).

Jednak nie sądzę, aby staticCachebuforowało negatywne odpowiedzi (gdy plik nie istnieje), więc nie pomaga, jeśli umieścisz staticCachepowyżej routerbez zamontowania go na ścieżce.

Podobnie jak w przypadku wszystkich pytań dotyczących wydajności, zmierz i testuj swoją rzeczywistą aplikację (pod obciążeniem), aby zobaczyć, gdzie naprawdę są wąskie gardła.


Ekspres 4

Express 4.0 usuwa app.router . Wszystkie oprogramowanie pośrednie ( app.use) i trasy ( app.geti in.) Są teraz przetwarzane w dokładnie takiej kolejności, w jakiej zostały dodane.

Innymi słowy:

Wszystkie metody routingu zostaną dodane w kolejności, w jakiej występują. Nie powinieneś tego robić app.use(app.router). Eliminuje to najczęstszy problem z Express.

Innymi słowy, miksowanie app.use()i app[VERB]()będzie działać dokładnie w kolejności, w jakiej są wywoływane.

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

Przeczytaj więcej o zmianach w Express 4.

josh3736
źródło
2
routerIdzie w jednym miejscu. Jeśli po raz pierwszy zadzwonisz app.get(lub postinne osoby), jeszcze nie used app.router, Express doda to dla ciebie.
josh3736
4
@MikeCauser: Nie, ponieważ obciążenie związane z dostępem do dysku (aby sprawdzić, czy plik istnieje) jest większe niż obciążenie wywołania funkcji. W moim teście narzut ten wyniósł 1 ms na nieobciążonym serwerze. Jest to znacznie wyższe w przypadku obciążenia, gdy żądania będą konkurować o dostęp do dysku. Z staticPO router, pytanie o drugiej pośredniej staje się nieistotna, ponieważ musi być powyżej routera.
josh3736
2
Cudowne wyjaśnienie! Dziękuję bardzo!
Kirn
3
app.routerjest usuwany w bieżącej gałęzi master, która będzie express-4.0 . Każda trasa staje się oddzielnym oprogramowaniem pośrednim.
yanychar
3
Jeszcze jedno wyjaśnienie, gdy nad tym pracuję. W Express 4 można przypisać wiele tras do routera, a następnie w celu korzystania z routera router otrzymuje ścieżkę root i umieszczany jest w stosie oprogramowania pośredniego poprzez app.use (ścieżka, router). Umożliwia to powiązanym trasom korzystanie z własnego routera i przypisanie ścieżki podstawowej jako jednostki. Gdybym to lepiej zrozumiał, zaproponowałbym opublikowanie kolejnej odpowiedzi. Ponownie otrzymuję to od scotch.io/tutorials/javascript/...
Joe Lapp,
2

Routing oznacza określenie, w jaki sposób aplikacja odpowiada na żądanie klienta do określonego punktu końcowego, którym jest identyfikator URI (lub ścieżka) i określona metoda żądania HTTP (GET, POST itd.). Każda trasa może mieć jedną lub więcej funkcji obsługi, które są wykonywane, gdy trasa jest dopasowana.

W Express 4.0 Router mamy większą niż kiedykolwiek elastyczność w definiowaniu naszych tras.

express.Router () jest używany wielokrotnie do definiowania grup tras.

trasa używana jako oprogramowanie pośrednie do przetwarzania żądań.

trasa używana jako oprogramowanie pośrednie do sprawdzania poprawności parametrów za pomocą „.param ()”.

app.route () używany jako skrót do routera do definiowania wielu żądań na trasie

kiedy używamy app.route (), dołączamy naszą aplikację do tego routera.

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')
})
Parth Raval
źródło
0

W ekspresowej wersji 4 możemy łatwo zdefiniować trasy w następujący sposób:

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;

W server.jszaimportowaliśmy obiekt routera route.jspliku i zastosowaliśmy go w następujący sposób w server.js:

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

Teraz wszystkie trasy w route.jsmają następujący podstawowy adres URL:

http: // localhost: 3000 / route

Dlaczego takie podejście:

Główną zaletą takiego podejścia jest to, że teraz nasza aplikacja jest bardziej modułowa . Wszystkie moduły obsługi trasy dla określonej trasy można teraz umieścić w różnych plikach, co sprawia, że ​​wszystko jest łatwiejsze w utrzymaniu i łatwiejsze do znalezienia.

Willem van der Veen
źródło