【Node.js】Node.js入门(六):Express中间件函数

1、简述

啥是中间件函数,先不百度,想象理解下:在web请求-响应的循环中,会根据请求调用回调函数,并返回响应,回调函数会有嵌套调用,把这些函数固定参数形式,就是中间件。
以上是小白为了做心理上的假定合理性猜测,等深入了解后,再改正。也希望大神们留言指教。

中间件函数完成以下功能:

执行任何代码。
对请求和响应对象进行更改。
结束请求-响应周期。
调用堆栈中的下一个中间件。

Express中间件函数接受三个参数:请求对象(req)、响应对象 (res)、next()函数。
如果当前中间件函数没有结束请求-响应周期,它必须调用next()将控制传递给下一个中间件函数。否则,请求将被搁置。

2、示例:Hello World

示例功能:每次应用程序收到一个请求,它打印消息“LOGGED”到终端。

中间件加载的顺序很重要:首先加载的中间件函数也会首先执行。
如果myLogger是在到根路径的路由之后加载的,那么请求永远不会到达它,应用程序也不会打印“LOGGED”,因为根路径的路由处理程序终止了请求-响应周期。
中间件函数myLogger只是打印一条消息,然后通过调用next()函数将请求传递给堆栈中的下一个中间件函数。

var express = require('express')
var app = express()

var myLogger = function (req, res, next) {
  console.log('LOGGED')
  next()
}

app.use(myLogger)

app.get('/', function (req, res) {
  res.send('Hello World!')
})

app.listen(3000)

3、示例:返回值创建、使用

示例功能是在web页面中显示时间,和上例代码结构一样,不同点是:这个示例演示了返回值在回调函数中如何传递。下例中req.requestTime在中间件函数中创建并设置为当前时间,在回调函数中直接使用。对于C程序员来说,这种使用方式好神奇啊!

var express = require('express')
var app = express()

var requestTime = function (req, res, next) {
  req.requestTime = Date.now()
  next()
}

app.use(requestTime)

app.get('/', function (req, res) {
  var responseText = 'Hello World!<br>'
  responseText += '<small>Requested at: ' + req.requestTime + '</small>'
  res.send(responseText)
})

app.listen(3000)

4、示例:错误处理

本示例功能:创建一个中间件函数,该函数验证传入的cookie并在cookie无效时发送一个400响应。

本示例使用cookie解析器中间件从req对象解析传入的cookie,并将它们传递给cookieValidator函数。validateCookies中间件返回一个Promise,在拒绝时将自动触发我们的错误处理程序。

注意在cookieValidator(req.cookies)之后调用next()。这确保了在cookieValidator解析时,堆栈中的下一个中间件将被调用,即异步执行。
如果将任何东西传递给next()函数(字符串’route’或’router’除外),Express将认为当前请求是一个错误,并将跳过所有剩余的非错误处理路由和中间件函数。(这个功能又很突然,怎么就认为是错误了,没有看到条件判断啊?疑问先留着,待以后解决)

async function cookieValidator (cookies) {
  try {
    await externallyValidateCookie(cookies.testCookie)
  } catch {
    throw new Error('Invalid cookies')
  }
}

var express = require('express')
var cookieParser = require('cookie-parser')
var cookieValidator = require('./cookieValidator')

var app = express()

async function validateCookies (req, res, next) {
  await cookieValidator(req.cookies)
  next()
}

app.use(cookieParser())

app.use(validateCookies)

// 错误处理
app.use(function (err, req, res, next) {
  res.status(400).send(err.message)
})

app.listen(3000)

5、示例:使中间件可配置

创建hello.js中间件文件,在这个文件中使用module.exports导出中间件函数,根据传入的函数参数,在中间件函数中执行不同功能

module.exports = function (options) {
  return function (req, res, next) {
    // 在这里根据下面主程序传入的option1、option2来执行不同功能,实现中间件可配置。
    next()
  }
}

在app主程序中使用

var mw = require('./hello.js')
app.use(mw({ option1: '1', option2: '2' }))

6、应用层中间件

1)示例展示:没有指定路由,并且可以响应任何请求的中间件。

var express = require('express')
var app = express()

app.use(function (req, res, next) {
  console.log('Time:', Date.now())
  next()
})

2)示例展示:一个挂载在/user/:id路径上的中间件函数。该函数对/user/:id路径上的任何类型的HTTP请求执行。

app.use('/user/:id', function (req, res, next) {
  console.log('Request Type:', req.method)
  next()
})

3)示例展示:在/user/:id路由上,处理get请求

app.get('/user/:id', function (req, res, next) {
  res.send('USER')
})

4)示例展示:中间件堆栈,即串联多个处理函数

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()
})

5)示例展示:结束请求-响应周期

下面的示例为到/user/:id路径的GET请求定义了两条路由。第二个路由永远不会被调用,因为第一个路由最后没有调用next()结束了请求-响应周期。

app.get('/user/:id', function (req, res, next) {
  console.log('ID:', req.params.id)
  next()
}, function (req, res, next) {
  res.send('User Info')
})

app.get('/user/:id', function (req, res, next) {
  res.send(req.params.id)
})

6)示例展示:跳过中间件堆栈中其余中间件函数

可以调用next(‘route’)将控制传递给下一个路由。注意:next(‘route’)只在使用app.METHOD()或router.METHOD()函数加载的中间件函数中工作。

app.get('/user/:id', function (req, res, next) {
  // 如果用户ID为0,则跳转到下一条路由
  if (req.params.id === '0') next('route')
  // 如果用户ID为0,则跳转到下一条路由
  else next()
}, function (req, res, next) {
  res.send('regular')
})

app.get('/user/:id', function (req, res, next) {
  res.send('special')
})

7)示例展示:中间件函数数组

为了可重用性,中间件也可以声明在数组中。
这个例子展示了一个带有中间件子堆栈的数组,该数组处理到/user/:id路径的GET请求

function logOriginalUrl (req, res, next) {
  console.log('Request URL:', req.originalUrl)
  next()
}

function logMethod (req, res, next) {
  console.log('Request Type:', req.method)
  next()
}

var logStuff = [logOriginalUrl, logMethod]
app.get('/user/:id', logStuff, function (req, res, next) {
  res.send('User Info')
})

7、路由层中间件

路由层中间件与应用层中间件的工作方式相同,只是它被绑定到express.Router()的实例上。

var router = express.Router()

通过使用router.use()和router.METHOD()函数加载路由层中间件。

下面的示例和=6=中应用层中间件的示例基本相同:

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

// 没有挂载路径的中间件函数。对于每个向路由器的请求都会执行此代码
router.use(function (req, res, next) {
  console.log('Time:', Date.now())
  next()
})

// 中间件子堆栈会显示到/user/:id路径的任何类型的HTTP请求的请求信息
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()
})

// 处理到/user/:id路径的GET请求的中间件子堆栈
router.get('/user/:id', function (req, res, next) {
  // 如果用户ID为0,则跳转到下一个路由器
  if (req.params.id === '0') next('route')
  // 否则,将控制传递给此堆栈中的下一个中间件函数
  else next()
}, function (req, res, next) {
  // 渲染普通页面
  res.render('regular')
})

// user/:id路径的处理程序,它呈现一个特殊的页面
router.get('/user/:id', function (req, res, next) {
  console.log(req.params.id)
  res.render('special')
})

// /user/:id路径的处理程序,它呈现一个特殊的页面
app.use('/', router)

要跳过路由器的其他中间件函数,调用next(‘router’)将控制传递回路由器实例。
这个例子展示了一个中间件堆栈,它处理到/user/:id路径的GET请求

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

// 用检查谓词路由器,并在需要时提取
router.use(function (req, res, next) {
  if (!req.headers['x-auth']) return next('router')
  next()
})

router.get('/user/:id', function (req, res) {
  res.send('hello, user!')
})

// 执行:next('router')
app.use('/admin', router, function (req, res) {
  res.sendStatus(401)
})

8、错误处理中间件

错误处理中间件总是接受四个参数。必须提供四个参数将其标识为错误处理中间件函数。即使不需要使用下一个对象,也必须指定它来维护签名。否则,下一个对象将被解释为常规中间件,将无法处理错误。

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

9、内置的中间件

Express有以下内置的中间件:

express.static:服务于静态资产,如HTML文件、图像等。
express.json:使用内置json中间件解析传入请求。
express.urlencoded:使用内置url编码中间件解析传入的请求

10、第三方中间件

使用第三方中间件为Express应用程序添加功能。

先安装,再加载:
下面的示例演示了安装和加载中间件函数cookie-parser。

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

// 加载cookie解析中间件
app.use(cookieParser())

常用第三方中间件参见:https://www.expressjs.com.cn/resources/middleware.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

郭老二

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值