Express 中間件

2024-12-03 18:01 更新

使用中間件

Express 是一個(gè)自身功能極簡(jiǎn),完全是由路由和中間件構(gòu)成一個(gè)的 web 開發(fā)框架:從本質(zhì)上來(lái)說(shuō),一個(gè) Express 應(yīng)用就是在調(diào)用各種中間件。

中間件(Middleware) 是一個(gè)函數(shù),它可以訪問(wèn)請(qǐng)求對(duì)象(request object (req)), 響應(yīng)對(duì)象(response object (res)), 和 web 應(yīng)用中處于請(qǐng)求-響應(yīng)循環(huán)流程中的中間件,一般被命名為 next 的變量。

中間件的功能包括:

  • 執(zhí)行任何代碼。
  • 修改請(qǐng)求和響應(yīng)對(duì)象。
  • 終結(jié)請(qǐng)求-響應(yīng)循環(huán)。
  • 調(diào)用堆棧中的下一個(gè)中間件。

如果當(dāng)前中間件沒(méi)有終結(jié)請(qǐng)求-響應(yīng)循環(huán),則必須調(diào)用 next() 方法將控制權(quán)交給下一個(gè)中間件,否則請(qǐng)求就會(huì)掛起。

Express 應(yīng)用可使用如下幾種中間件:

使用可選則掛載路徑,可在應(yīng)用級(jí)別或路由級(jí)別裝載中間件。另外,你還可以同時(shí)裝在一系列中間件函數(shù),從而在一個(gè)掛載點(diǎn)上創(chuàng)建一個(gè)子中間件棧。

應(yīng)用級(jí)中間件

應(yīng)用級(jí)中間件綁定到 app 對(duì)象 使用 app.use()app.METHOD(),其中, METHOD 是需要處理的 HTTP 請(qǐng)求的方法,例如 GET, PUT, POST 等等,全部小寫。例如:

var app = express();

// 沒(méi)有掛載路徑的中間件,應(yīng)用的每個(gè)請(qǐng)求都會(huì)執(zhí)行該中間件
app.use(function (req, res, next) {
  console.log('Time:', Date.now());
  next();
});

// 掛載至 /user/:id 的中間件,任何指向 /user/:id 的請(qǐng)求都會(huì)執(zhí)行它
app.use('/user/:id', function (req, res, next) {
  console.log('Request Type:', req.method);
  next();
});

// 路由和句柄函數(shù)(中間件系統(tǒng)),處理指向 /user/:id 的 GET 請(qǐng)求
app.get('/user/:id', function (req, res, next) {
  res.send('USER');
});

下面這個(gè)例子展示了在一個(gè)掛載點(diǎn)裝載一組中間件。

// 一個(gè)中間件棧,對(duì)任何指向 /user/:id 的 HTTP 請(qǐng)求打印出相關(guān)信息
app.use('/user/:id', function(req, res, next) {
  console.log('Request URL:', req.originalUrl);
  next();
}, function (req, res, next) {
  console.log('Request Type:', req.method);
  next();
});

作為中間件系統(tǒng)的路由句柄,使得為路徑定義多個(gè)路由成為可能。在下面的例子中,為指向 /user/:id 的 GET 請(qǐng)求定義了兩個(gè)路由。第二個(gè)路由雖然不會(huì)帶來(lái)任何問(wèn)題,但卻永遠(yuǎn)不會(huì)被調(diào)用,因?yàn)榈谝粋€(gè)路由已經(jīng)終止了請(qǐng)求-響應(yīng)循環(huán)。

// 一個(gè)中間件棧,處理指向 /user/:id 的 GET 請(qǐng)求
app.get('/user/:id', function (req, res, next) {
  console.log('ID:', req.params.id);
  next();
}, function (req, res, next) {
  res.send('User Info');
});

// 處理 /user/:id, 打印出用戶 id
app.get('/user/:id', function (req, res, next) {
  res.end(req.params.id);
});

如果需要在中間件棧中跳過(guò)剩余中間件,調(diào)用 next('route') 方法將控制權(quán)交給下一個(gè)路由。注意next('route') 只對(duì)使用 app.VERB()router.VERB() 加載的中間件有效。

// 一個(gè)中間件棧,處理指向 /user/:id 的 GET 請(qǐng)求
app.get('/user/:id', function (req, res, next) {
  // 如果 user id 為 0, 跳到下一個(gè)路由
  if (req.params.id == 0) next('route');
  // 否則將控制權(quán)交給棧中下一個(gè)中間件
  else next(); //
}, function (req, res, next) {
  // 渲染常規(guī)頁(yè)面
  res.render('regular');
});

// 處理 /user/:id, 渲染一個(gè)特殊頁(yè)面
app.get('/user/:id', function (req, res, next) {
  res.render('special');
});

路由級(jí)中間件

路由級(jí)中間件和應(yīng)用級(jí)中間件一樣,只是它綁定的對(duì)象為 express.Router()

var router = express.Router();

路由級(jí)使用 router.use()router.VERB() 加載。

上述在應(yīng)用級(jí)創(chuàng)建的中間件系統(tǒng),可通過(guò)如下代碼改寫為路由級(jí):

var app = express();
var router = express.Router();

// 沒(méi)有掛載路徑的中間件,通過(guò)該路由的每個(gè)請(qǐng)求都會(huì)執(zhí)行該中間件
router.use(function (req, res, next) {
  console.log('Time:', Date.now());
  next();
});

// 一個(gè)中間件棧,顯示任何指向 /user/:id 的 HTTP 請(qǐng)求的信息
router.use('/user/:id', function(req, res, next) {
  console.log('Request URL:', req.originalUrl);
  next();
}, function (req, res, next) {
  console.log('Request Type:', req.method);
  next();
});

// 一個(gè)中間件棧,處理指向 /user/:id 的 GET 請(qǐng)求
router.get('/user/:id', function (req, res, next) {
  // 如果 user id 為 0, 跳到下一個(gè)路由
  if (req.params.id == 0) next('route');
  // 負(fù)責(zé)將控制權(quán)交給棧中下一個(gè)中間件
  else next(); //
}, function (req, res, next) {
  // 渲染常規(guī)頁(yè)面
  res.render('regular');
});

// 處理 /user/:id, 渲染一個(gè)特殊頁(yè)面
router.get('/user/:id', function (req, res, next) {
  console.log(req.params.id);
  res.render('special');
});

// 將路由掛載至應(yīng)用
app.use('/', router);

錯(cuò)誤處理中間件

錯(cuò)誤處理中間件有 4 個(gè)參數(shù),定義錯(cuò)誤處理中間件時(shí)必須使用這 4 個(gè)參數(shù)。即使不需要 next 對(duì)象,也必須在簽名中聲明它,否則中間件會(huì)被識(shí)別為一個(gè)常規(guī)中間件,不能處理錯(cuò)誤。

錯(cuò)誤處理中間件和其他中間件定義類似,只是要使用 4 個(gè)參數(shù),而不是 3 個(gè),其簽名如下: (err, req, res, next)

app.use(function(err, req, res, next) {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

請(qǐng)參考 錯(cuò)誤處理 一章了解更多關(guān)于錯(cuò)誤處理中間件的內(nèi)容。

內(nèi)置中間件

從 4.x 版本開始,, Express 已經(jīng)不再依賴 Connect 了。除了 express.static, Express 以前內(nèi)置的中間件現(xiàn)在已經(jīng)全部單獨(dú)作為模塊安裝使用了。請(qǐng)參考 中間件列表。

express.static(root, [options])

express.static 是 Express 唯一內(nèi)置的中間件。它基于 serve-static,負(fù)責(zé)在 Express 應(yīng)用中提托管靜態(tài)資源。

參數(shù) root 指提供靜態(tài)資源的根目錄。

可選的 options 參數(shù)擁有如下屬性。

屬性 描述 類型 缺省值
dotfiles 是否對(duì)外輸出文件名以點(diǎn)(.)開頭的文件。可選值為 “allow”、“deny” 和 “ignore” String “ignore”
etag 是否啟用 etag 生成 Boolean true
extensions 設(shè)置文件擴(kuò)展名備份選項(xiàng) Array []
index 發(fā)送目錄索引文件,設(shè)置為 false 禁用目錄索引。 Mixed “index.html”
lastModified 設(shè)置 Last-Modified 頭為文件在操作系統(tǒng)上的最后修改日期??赡苤禐?truefalse。 Boolean true
maxAge 以毫秒或者其字符串格式設(shè)置 Cache-Control 頭的 max-age 屬性。 Number 0
redirect 當(dāng)路徑為目錄時(shí),重定向至 “/”。 Boolean true
setHeaders 設(shè)置 HTTP 頭以提供文件的函數(shù)。 Function  

下面的例子使用了 express.static 中間件,其中的 options 對(duì)象經(jīng)過(guò)了精心的設(shè)計(jì)。

var options = {
  dotfiles: 'ignore',
  etag: false,
  extensions: ['htm', 'html'],
  index: false,
  maxAge: '1d',
  redirect: false,
  setHeaders: function (res, path, stat) {
    res.set('x-timestamp', Date.now());
  }
}

app.use(express.static('public', options));

每個(gè)應(yīng)用可有多個(gè)靜態(tài)目錄。

app.use(express.static('public'));
app.use(express.static('uploads'));
app.use(express.static('files'));

更多關(guān)于 serve-static 和其參數(shù)的信息,請(qǐng)參考 serve-static 文檔。

第三方中間件

通過(guò)使用第三方中間件從而為 Express 應(yīng)用增加更多功能。

安裝所需功能的 node 模塊,并在應(yīng)用中加載,可以在應(yīng)用級(jí)加載,也可以在路由級(jí)加載。

下面的例子安裝并加載了一個(gè)解析 cookie 的中間件: cookie-parser

$ npm install cookie-parser
var express = require('express');
var app = express();
var cookieParser = require('cookie-parser');

// 加載用于解析 cookie 的中間件
app.use(cookieParser());

請(qǐng)參考 第三方中間件 獲取 Express 中經(jīng)常用到的第三方中間件列表。

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

掃描二維碼

下載編程獅App

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

編程獅公眾號(hào)