官术网_书友最值得收藏!

4.3 路由

路由是指應用程序如何根據指定的路由路徑和指定的HTTP請求方法(GET和POST等)來處理請求。

在Express應用中,每個路由可以有一個或多個處理函數,這些函數會在路由匹配時執行。

路由采用以下結構定義:

app.METHOD(PATH, HANDLER)

· app:應用實例。

· METHOD:小寫get和post等的HTTP請求方法。

· PATH:路由路徑。

· HANDLER:路由匹配時執行的函數。

4.3.1 路由方法

路由方法是從HTTP方法派生的,以下是GET和POST方法定義路由的示例:

app.get('/', (req, resp) => {
 resp.send('GET請求');
});

app.post('/', (req, resp) => {
 resp.send('POST請求');
});

Express支持所有的HTTP請求方法:

· get

· post

· head

· options

· delete

· put

· patch

如果需要使用一個路由來處理所有的請求方法,則可以調用app.all():

app.all('/', (req, resp) => {
  resp.send('請求首頁');
});

4.3.2 路由路徑

路由路徑結合請求方法,定義了可以發出請求的地址。路由路徑可以是字符串、字符串模式或正則表達式。

查詢字符串(一般稱為GET參數)不是路由路徑的一部分。

(1)以下是一些基于字符串的路由路徑的示例。

以下路由路徑會將請求匹配到根路由/:

app.get('/', (req, resp) => {
 resp.send('主頁');
});

以下路由路徑會將請求匹配到/about:

app.get('/about', (req, resp) => {
 resp.send('關于頁面');
});

以下路由路徑可以將請求匹配到/random.txt文件:

app.get('/random.txt', (req, resp) => {
  resp.send('random.txt');
});

字符串模式可以“認為”是正則表達式的子集,支持部分正則表達式語法。

(2)以下是一些基于字符串模式的路由路徑示例。

以下路由路徑將與/acd和/abcd相匹配。“?”號在正則表達式中代表“至多一個”,示例代碼中就是匹配“至多一個b”:

app.get('/ab?cd', (req, resp) => {
 resp.send('ab?cd');
});

以下路由路徑將與/abcd、/abbcd、/abbbcd等等相匹配。+在正則表達式中代表“至少一個”,示例代碼中就是匹配“至少一個b”:

app.get('/ab+cd', (req, resp) => {
  resp.send('ab+cd');
});

以下路由路徑將與/abcd和/ad相匹配。()在正則表達式中代表分組,示例代碼中就是“要么有一個bc,要么沒有bc”:

app.get('/a(bc)?d', (req, resp) => {
 resp.send('a(bc)?d');
});

(3)以下是一些基于正則表達式的路由路徑示例。

以下路由路徑將與任何帶有user的請求鏈接相匹配:

app.get(/user/, (req, resp) => {
 resp.send('/user/');
});

以下路由路徑將嚴格與/admin匹配:

app.get(/^\/admin$/, (req, resp) => {
    resp.send('/^\/admin$/');
});

4.3.3 路由參數

路由參數用于捕獲URL中各位置的值。捕獲的值將填充到req.params對象中,并將路由路徑中指定的route參數名稱作為req.params對象的鍵。

app.get('/users/:userId/timelines/:timelineId', (req, resp) => {
 resp.json(req.params);
});

訪問:http://localhost:8080/users/1/timelines/1,將得到以下響應:

{
 "userId": "1",
 "timelineId": "1"
}

路由參數的名稱必須由[A-Za-z0-9_](也就是大小寫字母、數字、下畫線)組成。

字符串和字符串模式路由路徑中的中劃線“-”和點“.”無特殊意義,Express按照字面意思處理這兩個字符。因為在正則表達式中這兩個字符有特殊意義,特此說明以防止混淆。

app.get('/users/:firstName.:lastName', (req, resp) => {
  resp.json(req.params);
});

訪問http://localhost:8080/users/lei.xia,將得到以下響應:

{
  "firstName": "lei",
  "lastName": "xia"
}

在/users/:userId/timelines/:timelineId例子中,預期匹配的是數字ID類型的參數,但是由于沒有類型限制,字符串形式的參數也會匹配到。如果不限制參數類型,容易引發類型問題。

在路由參數后使用正則表達式可以限制參數類型,不滿足類型的參數無法匹配該路由。

比如上述例子中,我們限制userId和timelineId為數字類型,可以使用以下代碼:

app.get('/users/:userId(\\d+)/timelines/:timelineId(\\d+)', (req, resp) => {
    resp.json(req.params);
});

訪問http://localhost:8080/users/1/timelines/1,將得到以下響應:

{
  "userId": "1",
  "timelineId": "1"
}

訪問http://localhost:8080/users/1a/timelines/1,將得到以下響應:

Cannot GET /users/1a/timelines/1

因為1a與(\d+)不匹配。

4.3.4 路由函數

路由方法和路由路徑匹配之后就會執行對應的路由函數,路由函數的簽名如下:

function(request, response, next)

· request Express:請求對象。

· response Express:響應對象。

· next:匹配的下一個路由函數(可選參數)。

1.單個路由函數

最簡單的路由函數,對請求處理后發出響應,結束本次請求處理。

app.get('/', (req, resp) => {
 resp.send('/');
});
2.多個路由函數

對于同一個路由,可以定義多個路由函數來處理,每個路由函數做一項工作。

不要忘記next()方法的調用,即使定義多個路由函數,只要第一個函數未調用next(),后續的路由函數都不會執行。

app.get('/', (req, resp, next) => {
    console.log(`${req.method} ${req.path}`);
    next();
}, (req, resp) => {
    resp.send('首頁');
});

如下示例定義了兩個路由函數,第一個函數打印了當前請求方法和請求路徑,然后調用next()執行下一個路由函數以響應此次請求。在上面的示例中,訪問首頁時終端會輸出“GET /”,之后會向客戶端輸出“首頁”字樣。Express中還可以使用函數數組來定義多個路由函數,上述例子的另外一種寫法如下,兩種寫法效果是一樣的。

function logger(req, resp, next) {
    console.log(`${req.method} ${req.path}`);
    next();
}

function home(req, resp) {
    resp.send('首頁');
}

// 設置路由
app.get('/', [logger, home]);
3.公共路由路徑

如果多個路由有同樣的路由路徑,只是請求方法不同,若分別為每種方法定義一次路由,則不利于模塊化。

app.get('/user/login', (req, resp) => {
 resp.send('登錄頁面');
});

app.post('/user/login', (req, resp) => {
 resp.send('登錄處理');
});

針對這種典型場景,Express提供了app.router()來處理:

4.模塊化的路由

使用Express提供的Router對象可以創建模塊化的對象,實現路由和入口JS的解耦。使用模塊化的路由有以下優點:

· 便于維護。

· 統一的路由前綴。

· 模塊化。

user.js用戶相關路由:

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

router.get('/login', (req, resp) => {
   resp.send('登錄');
});

router.get('/register', (req, resp) => {
   resp.send('注冊');
});

// 導出路由對象
module.exports = router;

timeline.js動態相關路由:

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

router.get('/list', (req, resp) => {
    resp.send('動態列表');
});

// 導出路由對象
module.exports = router;

index.js入口文件:

上述例子最終會生成以下路由:

· GET /user/login。

· GET /user/register。

· GET /timeline/list。

主站蜘蛛池模板: 禄丰县| 河曲县| 西藏| 怀集县| 和龙市| 华宁县| 东宁县| 洪湖市| 英德市| 蒙自县| 辛集市| 梅河口市| 乐业县| 离岛区| 金平| 山西省| 丹阳市| 建始县| 宜良县| 湟中县| 丘北县| 罗田县| 花垣县| 随州市| 郸城县| 郎溪县| 苏州市| 介休市| 于田县| 阳谷县| 荥阳市| 五台县| 广安市| 汝州市| 五华县| 和林格尔县| 东至县| 肃宁县| 蓬安县| 莱芜市| 铁岭市|