Express Tutorial Part 4: Routes and controllers

2018-05-15 17:26 更新
先決條件: 閱讀 Express /節(jié)點(diǎn)簡(jiǎn)介。 完成上一篇教程主題(包括快速教程第3部分:使用數(shù)據(jù)庫(kù)(使用Mongoose))。
目的: 了解如何創(chuàng)建簡(jiǎn)單的路由。 設(shè)置所有的URL端點(diǎn)。

概述

上一篇教程文章中,我們定義了 Mongoose 模型以與數(shù)據(jù)庫(kù)進(jìn)行交互,并使用(獨(dú)立)腳本創(chuàng)建一些初始 圖書(shū)館記錄。 我們現(xiàn)在可以編寫(xiě)代碼以向用戶(hù)呈現(xiàn)該信息。 我們需要做的第一件事是確定我們希望在我們的頁(yè)面中顯示哪些信息,然后定義返回這些資源的適當(dāng)?shù)腢RL。 然后,我們需要?jiǎng)?chuàng)建路由(URL處理程序)和視圖(模板)來(lái)顯示這些頁(yè)面。

下面的圖提供了處理HTTP請(qǐng)求/響應(yīng)時(shí)需要實(shí)現(xiàn)的數(shù)據(jù)和事物的主要流程的提示。 除了視圖和路由之外,圖中還顯示了"controllers" - 分離出代碼以從實(shí)際處理請(qǐng)求的代碼中路由請(qǐng)求的函數(shù)。

由于我們已經(jīng)創(chuàng)建了模型,我們需要?jiǎng)?chuàng)建的主要內(nèi)容是:

  • "Routes" to forward the supported requests (and any information encoded in request URLs) to the appropriate controller functions.
  • Controller functions to get the requested data from the models, create an HTML page displaying the data, and return it to the user to view in the browser.
  • Views (templates) used by the controllers to render the data.

最終,我們可能有頁(yè)面來(lái)顯示書(shū)籍,流派,作者和bookinstances的列表和詳細(xì)信息,以及創(chuàng)建,更新和刪除記錄的頁(yè)面。 這是一篇文章在一篇文章。 因此,本文大部分將集中在設(shè)置我們的路由和控制器返回"虛擬"內(nèi)容。 我們將在后續(xù)文章中擴(kuò)展控制器方法以使用模型數(shù)據(jù)。

下面的第一部分提供了有關(guān)如何使用Express"路由器"中間件的簡(jiǎn)要"初級(jí)"。 然后,當(dāng)我們?cè)O(shè)置LocalLibrary路由時(shí),我們將在以下部分使用該知識(shí)。

路由引物

路由是Express代碼的一部分,其將HTTP動(dòng)詞( GET , POST PUT , DELETE 等等),URL路徑/模式,以及被調(diào)用以處理該模式的函數(shù)。

有幾種方法來(lái)創(chuàng)建路由。 在本教程中,我們將使用 express.Router > 中間件,因?yàn)樗试S我們將網(wǎng)站特定部分的路由處理程序分組在一起,并使用公共路由前綴訪問(wèn)它們。 我們將所有的庫(kù)相關(guān)路由保存在一個(gè)"目錄"模塊中,如果我們添加了處理用戶(hù)帳戶(hù)或其他功能的路由,我們可以單獨(dú)分組。

注意:我們?cè)?a rel="external nofollow" target="_blank" > >快捷介紹> 創(chuàng)建路由處理程序。 除了為模塊化提供更好的支持(如下面第一小節(jié)所述),使用路由器與在 Express應(yīng)用程序?qū)ο?/em>上直接定義路由非常相似。

本節(jié)的其余部分提供了如何使用 Router 來(lái)定義路由的概述。

定義和使用單獨(dú)的路由模塊

下面的代碼提供了一個(gè)具體的例子,說(shuō)明如何創(chuàng)建一個(gè)路由模塊,然后在一個(gè) Express 應(yīng)用程序中使用它。

首先,我們?cè)诿麨?strong> wiki.js 的模塊中創(chuàng)建wiki的路線。 代碼首先導(dǎo)入Express應(yīng)用程序?qū)ο螅褂盟鼇?lái)獲取一個(gè) Router 對(duì)象,然后使用 get()方法添加一些路由到它。 最后模塊導(dǎo)出 Router 對(duì)象。

// wiki.js - Wiki route module

var express = require('express')
var router = express.Router()

// Home page route
router.get('/', function (req, res, next) {
  res.send('Wiki home page')
})

// About page route
router.get('/about', function (req, res, next) {
  res.send('About this wiki')
})

module.exports = router

注意:上面我們直接在路由器函數(shù)中定義我們的路由處理程序回調(diào)。 在LocalLibrary中,我們將在單獨(dú)的控制器模塊中定義這些回調(diào)。

要在我們的主要應(yīng)用程序文件中使用路由器模塊,我們首先使用 require()路由模塊( wiki.js )。 然后,我們?cè)?em> Express 應(yīng)用程序上調(diào)用 use()將路由器添加到中間件處理路徑,指定"wiki"的URL路徑。

var wiki = require('./wiki.js')
// ...
app.use('/wiki', wiki)

然后可以從 / wiki / / wiki / about / 訪問(wèn)在wiki路由模塊中定義的兩個(gè)路由。

路由函數(shù)

我們的模塊定義了幾個(gè)典型的路由功能。 使用 Router.get()方法定義"約"路由(如下所述),該方法僅響應(yīng)HTTP GET請(qǐng)求。 此方法的第一個(gè)參數(shù)是URL路徑,而第二個(gè)是回調(diào)函數(shù),如果接收到具有路徑的HTTP GET請(qǐng)求,將調(diào)用該函數(shù)。

router.get('/about', function (req, res, next) {
  res.send('About this wiki')
})

回調(diào)需要三個(gè)參數(shù)(通常如下所示: req , res next ),它將包含HTTP請(qǐng)求對(duì)象,HTTP響應(yīng), 和中間件鏈中的下一個(gè)功能。

此處的回調(diào)函數(shù)調(diào)用 send() 當(dāng)我們收到帶有路徑(\' / about\')的GET請(qǐng)求時(shí),返回字符串"About this wiki"的響應(yīng)。 有用于結(jié)束請(qǐng)求/響應(yīng)周期的其他響應(yīng)方法數(shù) 。 例如,您可以調(diào)用 res.json() / code>發(fā)送JSON響應(yīng)或 res.sendFile() a> 發(fā)送文件。 我們?cè)跇?gòu)建庫(kù)時(shí)最常使用的響應(yīng)方法是 render (),它使用模板和數(shù)據(jù)創(chuàng)建和返回HTML文件 - 我們將在后面的文章中進(jìn)一步討論這一點(diǎn)!

HTTP動(dòng)詞

上面的示例路由使用 Router.get()方法來(lái)響應(yīng)具有某個(gè)路徑的HTTP GET請(qǐng)求。

Router 還為所有其他HTTP動(dòng)詞提供路由方法,大多數(shù)使用方式完全相同: post() put >, delete(), options(), trace() (), mkcol(), move() proppatch(), unlock() , checkout() merge(), m- / code>, subscribe(), unsubscribe() code> connect()。

例如,下面的代碼與前面的 / about 路由一樣,但只響應(yīng)HTTP POST請(qǐng)求。

router.post('/about', function (req, res, next) {
  res.send('About this wiki')
})

路由路徑

路由路徑定義可以進(jìn)行請(qǐng)求的端點(diǎn)。 到目前為止,我們看到的例子只是字符串,并且使用的是完全一樣的:\'/\',\'/ about\',\'/ book\',\'/any-random.path\'。

路由路徑也可以是字符串模式。 字符串模式使用正則表達(dá)式語(yǔ)法的子集來(lái)定義要匹配的端點(diǎn)的模式。 下面列出了子集(注意,連字符( - )和點(diǎn)(。)由字符串路徑解釋):

  • ? : The endpoint must have 0 or more of the preceding character. E.g. a route path of '/ab?cd' will match endpoints acd , abcd, abbcd etc.
  • + : The endpoint must have 1 or more of the preceding character. E.g. a route path of '/ab+cd' will match endpoints abcd, abbcd, abbbcd, and so on.
  • * : The endpoint may have an arbitrary string where the * character is placed. E.g. a route path of 'ab*cd' will match endpoints abcd, abXcd, abSOMErandomTEXTcd, and so on.
  • () : Grouping match on a set of characters to perform another operation on. E.g. '/ab(cd)?e' will peform a ? match on (cd) —it will match abe, abcde, abcdcde, and so on.

路徑路徑也可以是JavaScript 正則表達(dá)式。 例如,下面的路由路徑將匹配 catfish dogfish 匹配,但不匹配 catflap , catfishhead 上。 請(qǐng)注意,正則表達(dá)式的路徑使用正則表達(dá)式語(yǔ)法(它不是以前情況下的帶引號(hào)的字符串)。

app.get(/.*fish$/, function (req, res) {
  ...
})

注意:LocalLibrary的大多數(shù)路由只使用字符串,而不是字符串模式和正則表達(dá)式。 我們還將使用下一節(jié)中討論的路由參數(shù)。

路由參數(shù)

路線參數(shù)是用于捕獲在網(wǎng)址中在其位置處指定的值的命名的網(wǎng)址片段。 命名段的前綴為冒號(hào),然后是名稱(chēng)(例如 / : your_parameter_name / 。)捕獲的值存儲(chǔ)在 req.params 對(duì)象使用參數(shù)名作為鍵(例如 req.params.your_parameter_name )。

例如,假設(shè)一個(gè)編碼為包含用戶(hù)和書(shū)籍信息的URL: http:// localhost:3000 / users / 34 / books / 8989 。 我們可以使用 userId bookId 路徑參數(shù)來(lái)提取此信息:

app.get('/users/:userId/books/:bookId', function (req, res) {
  // Access userId via: req.params.userId
  // Access bookId via: req.params.bookId
  res.send(req.params)
})

路由參數(shù)的名稱(chēng)必須由"字符"(A-Z,a-z,0-9和_)組成。

注意: / book / create 的網(wǎng)址將通過(guò) / book /:bookId (將提取"bookId" of\' create \')。 將使用與傳入U(xiǎn)RL匹配的第一個(gè)路由,因此如果您要分別處理 URL,則必須在您的 / book /:bookId 代碼>路由。

這就是開(kāi)始使用路由所需要的 - 如果需要,您可以在Express文檔中找到更多信息: >基本路由路由指南。 以下部分顯示了如何為L(zhǎng)ocalLibrary設(shè)置路由和控制器。

LocalLibrary所需的路徑

下面列出了我們最終需要用于我們網(wǎng)頁(yè)的網(wǎng)址,其中對(duì)象由每個(gè)模型的名稱(chēng)(book,bookinstance,genre,author), 是對(duì)象的復(fù)數(shù), 是默認(rèn)情況下給每個(gè)Mongoose模型實(shí)例賦予的唯一實(shí)例字段( _id )。

  • catalog/ — The home/index page.
  • catalog/<objects>/ — The list of all books, bookinstances, genres, or authors (e.g. /catalog/books/, /catalog/genres/, etc.)
  • catalog/<object>/<id> — The detail page for a specific book, bookinstance, genre, or author with the given _id field value (e.g. /catalog/book/584493c1f4887f06c0e67d37).
  • catalog/<object>/create — The form to create a new book, bookinstance, genre, or author (e.g. /catalog/book/create).
  • catalog/<object>/<id>/update — The form to update a specific book, bookinstance, genre, or author with the given _id field value (e.g. /catalog/book/584493c1f4887f06c0e67d37/update).
  • catalog/<object>/<id>/delete — The form to delete a specific book, bookinstance, genre, author with the given _id field value (e.g. /catalog/book/584493c1f4887f06c0e67d37/delete).

第一主頁(yè)和列表頁(yè)不編碼任何附加信息。 雖然返回的結(jié)果將取決于模型類(lèi)型和數(shù)據(jù)庫(kù)中的內(nèi)容,但運(yùn)行以獲取信息的查詢(xún)將始終相同(類(lèi)似地,用于對(duì)象創(chuàng)建的代碼運(yùn)行總是類(lèi)似的)。

相反,其他URL用于對(duì)特定文檔/模型實(shí)例進(jìn)行操作 - 這些URL對(duì)URL中的項(xiàng)目的標(biāo)識(shí)進(jìn)行編碼(如上所示的 。 我們將使用路徑參數(shù)提取編碼的信息,并將其傳遞給路由處理程序(在后面的文章中,我們將使用它來(lái)動(dòng)態(tài)確定從數(shù)據(jù)庫(kù)獲取什么信息)。 通過(guò)在我們的URL中編碼信息,我們只需要一個(gè)特定類(lèi)型的每個(gè)資源的一個(gè)路由(例如一個(gè)路由來(lái)處理每個(gè)單個(gè)書(shū)項(xiàng)目的顯示)。

注意:Express允許您以任何方式構(gòu)建網(wǎng)址 - 您可以按上面所示對(duì)網(wǎng)址正文中的信息進(jìn)行編碼,或使用URL GET 參數(shù)(例如 > / book /?id = 6 )。 無(wú)論您使用哪種方法,網(wǎng)址都應(yīng)保持干凈,邏輯和可讀(此處查看W3C建議 / a>)。

接下來(lái),我們?yōu)樗猩鲜鯱RL創(chuàng)建我們的路由處理程序回調(diào)函數(shù)和路由代碼。

創(chuàng)建路由處理程序回調(diào)函數(shù)

在我們定義我們的路由之前,我們首先創(chuàng)建他們將調(diào)用的所有dummy / skeleton回調(diào)函數(shù)。 回調(diào)將存儲(chǔ)在Books,BookInstances,Genres和Authors的單獨(dú)的"控制器"模塊中(您可以使用任何文件/模塊結(jié)構(gòu),但這對(duì)于該項(xiàng)目似乎是一個(gè)適當(dāng)?shù)牧6?。

首先在項(xiàng)目根目錄( / controllers )中為控制器創(chuàng)建一個(gè)文件夾,然后創(chuàng)建用于處理每個(gè)模型的單獨(dú)的控制器文件/模塊:

/express-locallibrary-tutorial  //the project root
  /controllers
    authorController.js
    bookController.js
    bookinstanceController.js
    genreController.js

作者控制器

打開(kāi) /controllers/authorController.js 文件,然后復(fù)制以下代碼:

var Author = require('../models/author');

// Display list of all Authors
exports.author_list = function(req, res, next) {
    res.send('NOT IMPLEMENTED: Author list');
};

// Display detail page for a specific Author
exports.author_detail = function(req, res, next) {
    res.send('NOT IMPLEMENTED: Author detail: ' + req.params.id);
};

// Display Author create form on GET
exports.author_create_get = function(req, res, next) {
    res.send('NOT IMPLEMENTED: Author create GET');
};

// Handle Author create on POST
exports.author_create_post = function(req, res, next) {
    res.send('NOT IMPLEMENTED: Author create POST');
};

// Display Author delete form on GET
exports.author_delete_get = function(req, res, next) {
    res.send('NOT IMPLEMENTED: Author delete GET');
};

// Handle Author delete on POST
exports.author_delete_post = function(req, res, next) {
    res.send('NOT IMPLEMENTED: Author delete POST');
};

// Display Author update form on GET
exports.author_update_get = function(req, res, next) {
    res.send('NOT IMPLEMENTED: Author update GET');
};

// Handle Author update on POST
exports.author_update_post = function(req, res, next) {
    res.send('NOT IMPLEMENTED: Author update POST');
};

該模塊首先需要我們稍后將使用的模型來(lái)訪問(wèn)和更新我們的數(shù)據(jù)。 然后它導(dǎo)出我們希望處理的每個(gè)URL的函數(shù)(創(chuàng)建,更新和刪除操作使用表單,因此還有其他方法來(lái)處理表單發(fā)布請(qǐng)求 - 稍后我們將在"表單文章"中討論這些方法 )。

所有函數(shù)都具有 Express中間件函數(shù)的標(biāo)準(zhǔn)形式,如果方法未完成請(qǐng)求,則調(diào)用請(qǐng)求,響應(yīng)和 next 函數(shù)的參數(shù) 循環(huán)(在所有這些情況下,它!)。 這些方法只返回一個(gè)字符串,表示相關(guān)的頁(yè)面尚未創(chuàng)建。 如果控制器函數(shù)期望接收路徑參數(shù),則這些包括在消息字符串中。

BookInstance controller

打開(kāi) /controllers/bookinstanceController.js 文件,并在以下代碼中復(fù)制(與 Author 控制器模塊具有相同的模式):

var BookInstance = require('../models/bookinstance');

// Display list of all BookInstances
exports.bookinstance_list = function(req, res, next) {
    res.send('NOT IMPLEMENTED: BookInstance list');
};

// Display detail page for a specific BookInstance
exports.bookinstance_detail = function(req, res, next) {
    res.send('NOT IMPLEMENTED: BookInstance detail: ' + req.params.id);
};

// Display BookInstance create form on GET
exports.bookinstance_create_get = function(req, res, next) {
    res.send('NOT IMPLEMENTED: BookInstance create GET');
};

// Handle BookInstance create on POST
exports.bookinstance_create_post = function(req, res, next) {
    res.send('NOT IMPLEMENTED: BookInstance create POST');
};

// Display BookInstance delete form on GET
exports.bookinstance_delete_get = function(req, res, next) {
    res.send('NOT IMPLEMENTED: BookInstance delete GET');
};

// Handle BookInstance delete on POST
exports.bookinstance_delete_post = function(req, res, next) {
    res.send('NOT IMPLEMENTED: BookInstance delete POST');
};

// Display BookInstance update form on GET
exports.bookinstance_update_get = function(req, res, next) {
    res.send('NOT IMPLEMENTED: BookInstance update GET');
};

// Handle bookinstance update on POST
exports.bookinstance_update_post = function(req, res, next) {
    res.send('NOT IMPLEMENTED: BookInstance update POST');
};

Genre controller

打開(kāi) /controllers/genreController.js 文件,并在以下文本中復(fù)制(與 Author BookInstance 文件格式相同):

var Genre = require('../models/genre');

// Display list of all Genre
exports.genre_list = function(req, res, next) {
    res.send('NOT IMPLEMENTED: Genre list');
};

// Display detail page for a specific Genre
exports.genre_detail = function(req, res, next) {
    res.send('NOT IMPLEMENTED: Genre detail: ' + req.params.id);
};

// Display Genre create form on GET
exports.genre_create_get = function(req, res, next) {
    res.send('NOT IMPLEMENTED: Genre create GET');
};

// Handle Genre create on POST
exports.genre_create_post = function(req, res, next) {
    res.send('NOT IMPLEMENTED: Genre create POST');
};

// Display Genre delete form on GET
exports.genre_delete_get = function(req, res, next) {
    res.send('NOT IMPLEMENTED: Genre delete GET');
};

// Handle Genre delete on POST
exports.genre_delete_post = function(req, res, next) {
    res.send('NOT IMPLEMENTED: Genre delete POST');
};

// Display Genre update form on GET
exports.genre_update_get = function(req, res, next) {
    res.send('NOT IMPLEMENTED: Genre update GET');
};

// Handle Genre update on POST
exports.genre_update_post = function(req, res, next) {
    res.send('NOT IMPLEMENTED: Genre update POST');
};

Book controller

打開(kāi) /controllers/bookController.js 文件,并在以下代碼中復(fù)制。 它遵循與其他控制器模塊相同的模式,但另外還具有用于顯示站點(diǎn)歡迎頁(yè)面的 index()函數(shù):

var Book = require('../models/book');

exports.index = function(req, res, next) {
    res.send('NOT IMPLEMENTED: Site Home Page');
};

// Display list of all books
exports.book_list = function(req, res, next) {
    res.send('NOT IMPLEMENTED: Book list');
};

// Display detail page for a specific book
exports.book_detail = function(req, res, next) {
    res.send('NOT IMPLEMENTED: Book detail: ' + req.params.id);
};

// Display book create form on GET
exports.book_create_get = function(req, res, next) {
    res.send('NOT IMPLEMENTED: Book create GET');
};

// Handle book create on POST
exports.book_create_post = function(req, res, next) {
    res.send('NOT IMPLEMENTED: Book create POST');
};

// Display book delete form on GET
exports.book_delete_get = function(req, res, next) {
    res.send('NOT IMPLEMENTED: Book delete GET');
};

// Handle book delete on POST
exports.book_delete_post = function(req, res, next) {
    res.send('NOT IMPLEMENTED: Book delete POST');
};

// Display book update form on GET
exports.book_update_get = function(req, res, next) {
    res.send('NOT IMPLEMENTED: Book update GET');
};

// Handle book update on POST
exports.book_update_post = function(req, res, next) {
    res.send('NOT IMPLEMENTED: Book update POST');
};

創(chuàng)建目錄路由模塊

接下來(lái),我們?yōu)長(zhǎng)ocalLibrary網(wǎng)站所需的所有網(wǎng)址創(chuàng)建路線,這將調(diào)用我們?cè)谏弦还?jié)中定義的控制器函數(shù)。

骨架已經(jīng)有 ./ routes 文件夾,其中包含 index 用戶(hù)的路線。 在此文件夾中創(chuàng)建另一個(gè)路線文件 catalog.js ,如圖所示。

/express-locallibrary-tutorial //the project root
  /routes
?   index.js
?   users.js
?   catalog.js

打開(kāi) /routes/catalog.js 并復(fù)制以下代碼:

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

// Require controller modules
var book_controller = require('../controllers/bookController');
var author_controller = require('../controllers/authorController');
var genre_controller = require('../controllers/genreController');
var book_instance_controller = require('../controllers/bookinstanceController');

/// BOOK ROUTES ///

/* GET catalog home page. */
router.get('/', book_controller.index);

/* GET request for creating a Book. NOTE This must come before routes that display Book (uses id) */
router.get('/book/create', book_controller.book_create_get);

/* POST request for creating Book. */
router.post('/book/create', book_controller.book_create_post);

/* GET request to delete Book. */
router.get('/book/:id/delete', book_controller.book_delete_get);

// POST request to delete Book
router.post('/book/:id/delete', book_controller.book_delete_post);

/* GET request to update Book. */
router.get('/book/:id/update', book_controller.book_update_get);

// POST request to update Book
router.post('/book/:id/update', book_controller.book_update_post);

/* GET request for one Book. */
router.get('/book/:id', book_controller.book_detail);

/* GET request for list of all Book items. */
router.get('/books', book_controller.book_list);

/// AUTHOR ROUTES ///

/* GET request for creating Author. NOTE This must come before route for id (i.e. display author) */
router.get('/author/create', author_controller.author_create_get);

/* POST request for creating Author. */
router.post('/author/create', author_controller.author_create_post);

/* GET request to delete Author. */
router.get('/author/:id/delete', author_controller.author_delete_get);

// POST request to delete Author
router.post('/author/:id/delete', author_controller.author_delete_post);

/* GET request to update Author. */
router.get('/author/:id/update', author_controller.author_update_get);

// POST request to update Author
router.post('/author/:id/update', author_controller.author_update_post);

/* GET request for one Author. */
router.get('/author/:id', author_controller.author_detail);

/* GET request for list of all Authors. */
router.get('/authors', author_controller.author_list);

/// GENRE ROUTES ///

/* GET request for creating a Genre. NOTE This must come before route that displays Genre (uses id) */
router.get('/genre/create', genre_controller.genre_create_get);

/* POST request for creating Genre. */
router.post('/genre/create', genre_controller.genre_create_post);

/* GET request to delete Genre. */
router.get('/genre/:id/delete', genre_controller.genre_delete_get);

// POST request to delete Genre
router.post('/genre/:id/delete', genre_controller.genre_delete_post);

/* GET request to update Genre. */
router.get('/genre/:id/update', genre_controller.genre_update_get);

// POST request to update Genre
router.post('/genre/:id/update', genre_controller.genre_update_post);

/* GET request for one Genre. */
router.get('/genre/:id', genre_controller.genre_detail);

/* GET request for list of all Genre. */
router.get('/genres', genre_controller.genre_list);

/// BOOKINSTANCE ROUTES ///

/* GET request for creating a BookInstance. NOTE This must come before route that displays BookInstance (uses id) */
router.get('/bookinstance/create', book_instance_controller.bookinstance_create_get);

/* POST request for creating BookInstance. */
router.post('/bookinstance/create', book_instance_controller.bookinstance_create_post);

/* GET request to delete BookInstance. */
router.get('/bookinstance/:id/delete', book_instance_controller.bookinstance_delete_get);

// POST request to delete BookInstance
router.post('/bookinstance/:id/delete', book_instance_controller.bookinstance_delete_post);

/* GET request to update BookInstance. */
router.get('/bookinstance/:id/update', book_instance_controller.bookinstance_update_get);

// POST request to update BookInstance
router.post('/bookinstance/:id/update', book_instance_controller.bookinstance_update_post);

/* GET request for one BookInstance. */
router.get('/bookinstance/:id', book_instance_controller.bookinstance_detail);

/* GET request for list of all BookInstance. */
router.get('/bookinstances', book_instance_controller.bookinstance_list);

module.exports = router;

該模塊需要Express,然后使用它創(chuàng)建一個(gè) Router 對(duì)象。 所有路由都在路由器上設(shè)置,然后導(dǎo)出。

使用路由器對(duì)象上的 .get() .post()方法定義路由。 所有路徑都使用字符串(我們不使用字符串模式或正則表達(dá)式),使用某些特定資源(例如書(shū))的路由使用路徑參數(shù)從URL獲取對(duì)象ID。

處理程序函數(shù)都是從我們?cè)谏弦还?jié)中創(chuàng)建的控制器模塊導(dǎo)入的。

更新索引路由模塊

我們已經(jīng)設(shè)置了所有的新路線,但我們?nèi)匀挥幸粭l到原始頁(yè)面的路線。 讓我們將它重定向到我們?cè)诼窂絓'/ catalog\'創(chuàng)建的新索引頁(yè)面。

打開(kāi) /routes/index.js 并使用以下功能替換現(xiàn)有路線。

/* GET home page. */
router.get('/', function(req, res) {
  res.redirect('/catalog');
});

注意:這是我們首次使用 redirect() 響應(yīng)方法。 這將重定向到指定的頁(yè)面,默認(rèn)情況下發(fā)送HTTP狀態(tài)代碼"302 Found"。 如果需要,可以更改返回的狀態(tài)代碼,并提供絕對(duì)路徑或相對(duì)路徑。

更新app.js

最后一步是將路由添加到中間件鏈。 我們?cè)?code> app.js 中這樣做。

打開(kāi) app.js ,并要求目錄路徑在其他路線下方(以粗體顯示):

var index = require('./routes/index');
var users = require('./routes/users');
var catalog = require('./routes/catalog');  //Import routes for "catalog" area of site

接下來(lái),將目錄路由添加到中間件堆棧下面的其他路由,如下面粗體顯示:

app.use('/', index);
app.use('/users', users);
app.use('/catalog', catalog);  // Add catalog routes to middleware chain.

注意:我們已將目錄模塊添加到路徑\'/ catalog\'。 這是在目錄模塊中定義的所有路徑的前面。 因此,例如,要訪問(wèn)圖書(shū)列表,URL將是: / catalog / books /

而已。 我們現(xiàn)在應(yīng)該為我們最終將在LocalLibrary網(wǎng)站上支持的所有URL啟用路由和骨干功能。

測(cè)試路由

要測(cè)試路線,首先使用您常用的方法啟動(dòng)網(wǎng)站

  • The default method
    //Windows
    SET DEBUG=express-locallibrary-tutorial:* & npm start
    
    // Mac OS or Linux
    DEBUG=express-locallibrary-tutorial:* npm start
    
  • If you previously set up nodemon, you can instead use:
    //Windows
    SET DEBUG=express-locallibrary-tutorial:* & npm run devstart
    
    // Mac OS or Linux
    DEBUG=express-locallibrary-tutorial:* npm run devstart
    

然后導(dǎo)航到多個(gè)LocalLibrary網(wǎng)址,并驗(yàn)證您沒(méi)有收到錯(cuò)誤頁(yè)面(HTTP 404)。 為方便起見(jiàn),下面列出了一小組網(wǎng)址:

概要

我們現(xiàn)在創(chuàng)建了我們網(wǎng)站的所有路由,以及虛擬控制器函數(shù),我們可以在后面的文章中填充完整的實(shí)現(xiàn)。 一路上,我們學(xué)到了很多關(guān)于Express路由的基本信息,以及一些用于構(gòu)造我們的路由和控制器的方法。

在下一篇文章中,我們將使用視圖(模板)和存儲(chǔ)在模型中的信息為網(wǎng)站創(chuàng)建一個(gè)適當(dāng)?shù)臍g迎頁(yè)面。

也可以看看

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)