黑人生命也是命。
支持平等正義倡議.

路由

路由是指應用程式的端點 (URI) 如何回應客戶端請求。若要了解路由簡介,請參閱 基本路由

您可以使用 Express app 物件的方法來定義路由,這些方法對應到 HTTP 方法;例如,app.get() 用於處理 GET 請求,而 app.post 用於處理 POST 請求。如需完整清單,請參閱 app.METHOD。您也可以使用 app.all() 來處理所有 HTTP 方法,並使用 app.use() 來指定中間件作為回呼函式(請參閱 使用中間件 以取得詳細資料)。

這些路由方法指定一個回呼函式(有時稱為「處理函式」),當應用程式收到指定路由(端點)和 HTTP 方法的請求時呼叫。換句話說,應用程式會「監聽」與指定路由和方法相符的請求,並在偵測到相符項時呼叫指定的回呼函式。

事實上,路由方法可以有多個回呼函式作為引數。使用多個回呼函式時,提供 next 作為回呼函式的引數並在函式的本體中呼叫 next() 以將控制權移交給下一個回呼函式非常重要。

下列程式碼是極為基本的路由範例。

const express = require('express')
const app = express()

// respond with "hello world" when a GET request is made to the homepage
app.get('/', (req, res) => {
  res.send('hello world')
})

路由方法

路由方法衍生自其中一個 HTTP 方法,並附加到 express 類別的執行個體。

下列程式碼是為應用程式的根目錄定義 GET 和 POST 方法的路由範例。

// GET method route
app.get('/', (req, res) => {
  res.send('GET request to the homepage')
})

// POST method route
app.post('/', (req, res) => {
  res.send('POST request to the homepage')
})

Express 支援與所有 HTTP 請求方法對應的方法:getpost 等。如需完整清單,請參閱 app.METHOD

有一個特殊的路由方法 app.all(),用於在路徑中載入中間層函式,以適用於所有 HTTP 請求方法。例如,下列處理常式會執行對路由「/secret」的請求,無論是使用 GET、POST、PUT、DELETE 或 http 模組 中支援的任何其他 HTTP 請求方法。

app.all('/secret', (req, res, next) => {
  console.log('Accessing the secret section ...')
  next() // pass control to the next handler
})

路由路徑

路由路徑與請求方法結合使用,定義可進行請求的端點。路由路徑可以是字串、字串模式或正規表示式。

字元 ?+*() 是其正規表示法對應項的子集。連字號 (-) 和句點 (.) 會由基於字串的路徑逐字解譯。

如果您需要在路徑字串中使用美元符號 ($),請將其封裝在 ([]) 中。例如,「/data/$book」請求的路徑字串會是「/data/([\$])book」。

Express 使用 path-to-regexp 來比對路由路徑;請參閱 path-to-regexp 文件,以了解定義路由路徑的所有可能性。Express Route Tester 是用於測試基本 Express 路由的便利工具,儘管它不支援模式比對。

查詢字串不屬於路由路徑的一部分。

以下是基於字串的路由路徑範例。

此路由路徑將比對對根路由 / 的請求。

app.get('/', (req, res) => {
  res.send('root')
})

此路由路徑將比對對 /about 的請求。

app.get('/about', (req, res) => {
  res.send('about')
})

此路由路徑將比對對 /random.text 的請求。

app.get('/random.text', (req, res) => {
  res.send('random.text')
})

以下是基於字串模式的路由路徑範例。

此路由路徑將比對 acdabcd

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

此路由路徑將比對 abcdabbcdabbbcd 等。

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

此路由路徑將比對 abcdabxcdabRANDOMcdab123cd 等。

app.get('/ab*cd', (req, res) => {
  res.send('ab*cd')
})

此路由路徑將比對 /abe/abcde

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

基於正規表示法的路由路徑範例

此路由路徑將比對任何包含「a」的內容。

app.get(/a/, (req, res) => {
  res.send('/a/')
})

此路由路徑將比對 butterflydragonfly,但不比對 butterflymandragonflyman 等。

app.get(/.*fly$/, (req, res) => {
  res.send('/.*fly$/')
})

路由參數

路由參數是命名的 URL 片段,用於擷取在 URL 中其位置指定的數值。擷取的數值會填入 req.params 物件中,其中路由參數的名稱會指定在路徑中,作為其各自的鍵。

Route path: /users/:userId/books/:bookId
Request URL: https://127.0.0.1:3000/users/34/books/8989
req.params: { "userId": "34", "bookId": "8989" }

若要定義帶有路由參數的路由,只需在路由的路徑中指定路由參數,如下所示。

app.get('/users/:userId/books/:bookId', (req, res) => {
  res.send(req.params)
})

路由參數的名稱必須由「字元」組成 ([A-Za-z0-9_]).

由於連字號 (-) 和句點 (.) 會被視為字面意思來詮釋,因此它們可以用於路由參數,以達到有用的目的。

Route path: /flights/:from-:to
Request URL: https://127.0.0.1:3000/flights/LAX-SFO
req.params: { "from": "LAX", "to": "SFO" }
Route path: /plantae/:genus.:species
Request URL: https://127.0.0.1:3000/plantae/Prunus.persica
req.params: { "genus": "Prunus", "species": "persica" }

若要更精確地控制路由參數可以比對的字串,您可以在括號中附加正規表示法 (())

Route path: /user/:userId(\d+)
Request URL: https://127.0.0.1:3000/user/42
req.params: {"userId": "42"}

由於正規表示法通常是字面字串的一部分,因此務必使用另一個反斜線來跳脫任何 \ 字元,例如 \\d+

在 Express 4.x 中,正規表示法中的 * 字元不會以通常的方式來詮釋。作為解決方法,請使用 {0,} 取代 *。這可能會在 Express 5 中修正。

路由處理常式

您可以提供多個回呼函式,它們會像 中間件 一樣處理要求。唯一的例外是,這些回呼函式可能會呼叫 next('route') 來略過其餘的路由回呼函式。您可以使用這個機制對路由施加前置條件,然後在沒有理由繼續執行目前的路由時,將控制權傳遞給後續路由。

路由處理程式可以是函式、函式陣列,或兩者的組合,如下列範例所示。

單一回呼函式可以處理路由。例如

app.get('/example/a', (req, res) => {
  res.send('Hello from A!')
})

多個回呼函式可以處理路由(請確定您指定了 next 物件)。例如

app.get('/example/b', (req, res, next) => {
  console.log('the response will be sent by the next function ...')
  next()
}, (req, res) => {
  res.send('Hello from B!')
})

函式陣列可以處理路由。例如

const cb0 = function (req, res, next) {
  console.log('CB0')
  next()
}

const cb1 = function (req, res, next) {
  console.log('CB1')
  next()
}

const cb2 = function (req, res) {
  res.send('Hello from C!')
}

app.get('/example/c', [cb0, cb1, cb2])

獨立函式和函式陣列的組合可以處理路由。例如

const cb0 = function (req, res, next) {
  console.log('CB0')
  next()
}

const cb1 = function (req, res, next) {
  console.log('CB1')
  next()
}

app.get('/example/d', [cb0, cb1], (req, res, next) => {
  console.log('the response will be sent by the next function ...')
  next()
}, (req, res) => {
  res.send('Hello from D!')
})

回應方法

下列表格中回應物件 (res) 上的方法可以將回應傳送給客戶端,並終止請求-回應循環。如果沒有從路由處理程式呼叫這些方法,客戶端請求將會持續掛起。

方法 說明
res.download() 提示下載檔案。
res.end() 結束回應程序。
res.json() 傳送 JSON 回應。
res.jsonp() 傳送支援 JSONP 的 JSON 回應。
res.redirect() 重新導向請求。
res.render() 呈現檢視範本。
res.send() 傳送各種類型的回應。
res.sendFile() 將檔案傳送為八位元組串流。
res.sendStatus() 設定回應狀態碼,並將其字串表示傳送為回應主體。

app.route()

您可以使用 app.route() 為路由路徑建立可串接的路由處理程式。由於路徑是在單一位置指定的,因此建立模組化路由很有幫助,且可以減少重複和錯字。如需關於路由的更多資訊,請參閱:Router() 文件

以下是使用 app.route() 定義的串接路由處理程式的範例。

app.route('/book')
  .get((req, res) => {
    res.send('Get a random book')
  })
  .post((req, res) => {
    res.send('Add a book')
  })
  .put((req, res) => {
    res.send('Update the book')
  })

express.Router

使用 express.Router 類別建立模組化、可掛載的路由處理常式。Router 執行個體是一個完整的中間件和路由系統;因此,它通常稱為「迷你應用程式」。

下列範例建立一個路由器作為模組,載入一個中間件函式,定義一些路由,並將路由器模組掛載在主應用程式的路徑上。

在應用程式目錄中建立一個名為 birds.js 的路由器檔案,內容如下

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

// middleware that is specific to this router
const timeLog = (req, res, next) => {
  console.log('Time: ', Date.now())
  next()
}
router.use(timeLog)

// define the home page route
router.get('/', (req, res) => {
  res.send('Birds home page')
})
// define the about route
router.get('/about', (req, res) => {
  res.send('About birds')
})

module.exports = router

然後,在應用程式中載入路由器模組

const birds = require('./birds')

// ...

app.use('/birds', birds)

應用程式現在可以處理對 /birds/birds/about 的要求,以及呼叫特定於路由的 timeLog 中間件函式。