Express中间件

目录

1.示例

服务器在接收到不同get请求之后,打印get请求的日志

const express = require('express')

const app = express()

// 中间件的顺序很重要
// req  请求对象  res 响应对象
// next 下一个中间件
app.use((req, res, next) => {
  console.log(req.method, req.url, Date.now())
  // 交出执行权,往后继续匹配执行
  next()
})

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

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

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

app.listen(3000, () => {
  console.log(`Server running at http://localhost:3000/`)
})

 

 2.概念解析

Express的最大特色,也是最重要的一个设计,就是中间件。中间件就是一个可以访问请求对象、响应对象和调用next方法的一个函数。

Express中间件和AOP(Aspect Oriented Programming)一样,就是都需要经过一些步骤来扩展或处理一些功能,但是不去修改自己的代码,不影响原有功能

利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率和可维护性

注意:如果当前的中间件功能没有结束请求-响应周期,则必须调用next()方法将控制权交给下一个中间件功能。否则,该请求将被挂起。

3.中间件分类 

应用程序级别中间件

const express = require('express')

const app = express()

...

app.listen(3000, () => {
  console.log(`Server running at http://localhost:3000/`)
})

①不关心请求路径 

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

 ②限定请求路径

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

③限定请求方法+请求路径 

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

④多个处理函数 

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

⑤为同一个路径定义多个处理中间件 

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.end(req.params.id)
})

因为send()已经结束了响应,所以后面的 res.end(req.params.id) 无效了

 

⑥要从路由器中间件堆栈中跳过其余中间件功能,要使用next('route')将控制权传递给下一条路由

app.get('/user/:id', function(req, res, next) {
  if (req.params.id === '0') next('route')
  else next()
}, function (req, res, next) {
  res.send('regular')
})

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

⑦中间件也可以在数组中声明为可重用

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('/users/:id', logStuff, function(req, res, next) {
  res.end('User Info')
})

 

路由级别中间件

对上面的一个小案例进行修改,将路由部分进行一个封装

router.js 

// 路由模块
const express = require('express')
const { getDb, saveDb } = require('./db')

// 1.创建路由实例,路由实例就相当于一个mini Express实例
const router = express.Router()

// 2.配置路由
router.get('/', async (req,res) => {
  ...    //原代码不变
})

router.get('/:id', async (req,res) => {
  ...    //原代码不变
})

router.post('/', async (req,res) => {
  ...    //原代码不变
})

// 3. 导出路由实例
module.exports = router

 app.js

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

const app = express()

// 解析表单请求体:application/json
app.use(express.json())
// 解析表单请求体:application/x-www-form-urlencoded
app.use(express.urlencoded())

// 挂载路由,并给路由限定访问前缀,不限定前缀:app.use(router)
app.use('/todos', router)

app.listen(3000, () => {
  console.log(`Server running at http://localhost:3000/`)
})

错误处理中间件

在上面的基础上修改

router.js 

将任何内容传给next()函数('route'除外),Express都会将当前请求视为错误,并且将跳过所有剩余的非错误处理路由和中间件函数,也就是会来到错误处理中间件。

// 路由模块
const express = require('express')
const { getDb, saveDb } = require('./db')

// 1.创建路由实例,路由实例就相当于一个mini Express实例
const router = express.Router()

// 2.配置路由
router.get('/', async (req,res,next) => {
  try {
    ...    //原代码不变
  } catch(err) {
    next(err)
  }
})

router.get('/:id', async (req,res,next) => {
  try {
    ...    //原代码不变
  } catch (err) {
    next(err)
  }
})

router.post('/', async (req,res,next) => {
  try {
    ...    //原代码不变
  } catch(err) {
    next(err)
  }
})

// 3. 导出路由实例
module.exports = router

app.js 

我这里顺便处理了请求内容找不到的404错误:在所有的路由之后配置

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

const app = express()

// 解析表单请求体:application/json
app.use(express.json())
// 解析表单请求体:application/x-www-form-urlencoded
app.use(express.urlencoded())

// 挂载路由,并给路由限定访问前缀,不限定前缀:app.use(router)
app.use('/todos', router)

// 通常在所有的路由之后配置处理404内容
app.use((req,res,next) => {
  res.status(404).send('404 Not Found.')
})

// 在所有中间件之后挂载错误处理中间件
// 这里想用err就必须有4个参数
app.use((err, req, res, next) => {
  console.log('错误', err)
  res.status(500).json({
    error: err.message
  })
})

app.listen(3000, () => {
  console.log(`Server running at http://localhost:3000/`)
})

内置中间件

express.json()                   解析Content-Type为application/json格式的请求体

express.urlencoded()        解析Content-Type为application/x-www-form-urlencoded格式的请求体

express.json()                   解析Content-Type为application/octet-stream格式的请求体

express.text()                    解析Content-Type为text/plain格式的请求体

express.static()                  托管静态资源文件

第三方中间件

具体有哪些以及怎么用可查看官网

这里以morgan为例,该中间件是用来打印日志的

先安装 npm install morgan,具体用法如下

app.js

const express = require('express')
const morgan = require('morgan')

const app = express()

app.use(morgan(':method :url :status :res[content-length] - :response-time ms'))

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

app.listen(3000, () => {
  console.log(`Server running at http://localhost:3000/`)
})
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

漂流の少年

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

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

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

打赏作者

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

抵扣说明:

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

余额充值