Express(二) ——中间件

Express(二) ——中间件


现在居住在深圳的社区被封了,整理下写的没发布的文章
个人博客:Express(二) ——中间件
Express(一) ——简单入门


在Express中,中间件是一个可以访问请求对象、响应对象和调用next方法的一个函数。

1. 简单例子(打印请求日志)

一个 Express 应用,就是由许许多多的中间件来完成的。

const express = require('express');

const app = express();

app.use((req, res, next) => {
  console.log(`请求日志:${req.method} ${req.url} ${new Date()}`);
  next(); // 放行
})

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

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

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

const port = 3000;

app.listen(port, () => {
  console.log(`http://localhost:${port}/`);
})

可以发现:任何请求进来都会先打印请求日志,然后才会执行具体的业务处理函数

image-20220209221247946

2. 中间件的组成

app.use('/', (req, res, next) => {  // 其中use可以是get、post等,用于限定请求路径
    next();		// 这个例子就是所有请求路径为根路径的请求都会通过这个中间件
    			// 如果当前中间件没有结束请求相应周期,则需要通过next()调用下一个中间件,否则,该请求将会被挂起
})

如果当前中间件没有结束请求相应周期,则需要通过next()调用下一个中间件,否则,该请求将会被挂起

3. 中间件功能

  • 执行任何代码
  • 修改request或response对象
  • 结束请求响应周期
  • 调用下一个中间件

4. 中间件分类

4.1 应用程序级别中间件

4.1.1 不做任何限定的中间件

即所有请求都会通过该中间件

app.use(function (req, res, next) {
  res.send('不做任何限定的中间件');
})
4.1.2 限定请求路径

即只有请求路径匹配才会通过该中间件

app.use('/user/:id', function (req, res, next) {
  res.send('限定请求路径的中间件');
})
4.1.3 限定请求方法 + 请求路径

不能只限定请求方法,因为app.get()第一个参数必须

app.get('/', (req, res) => {
  res.send('限定请求方法 + 请求路径的中间件');
})
4.1.4 多个处理函数
app.use(function (req, res, next) {
  console.log('第一次处理');
  next();    // 这个next()之后就是第二个处理函数
}, function (req, res, next) {
  console.log('第二次处理');
  next();    // 这个next()之后则是脱离当前处理栈,往后寻找匹配调用
})

也可以通过回调函数数组

const first = (req, res, next) => {
  console.log('第一次处理');
  next();
};

const second = (req, res, next) => {
  console.log('第二次处理');
  next();
};

app.use([first, second]);
4.1.5 多个路由处理函数
app.use('/', (req, res, next) => {
  console.log('第一个路由处理函数');
  next();   // 如果这里是res.end(),那么就会结束响应。第二个路由处理函数就没有机会执行
})
app.use('/', (req, res, next) => {
  console.log('第二个路由处理函数');
  res.end();
})
4.1.6 显示一个中间件子堆栈
app.get('/:id', function (req, res, next) {
  if (req.params.id === '0') {
    next('route');  // 跳过当前堆栈之后的所有中间件。即不执行后面的处理函数,而是直接去执行后面的路由处理函数
      			   // (处理函数和路由处理函数看上面的例子)
  } else {
    next();
  }
}, function (req, res, next) {
  res.send('regular');
})

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

上面例子中,动态参数id不为0时,第一个处理函数会调用next(),然后会执行第二个处理函数,然后会收到regular的响应。而当id为0时,会调用next(‘route’),会跳过当前堆栈之后的所有中间件。即不执行后面的处理函数,而是直接去执行后面的路由处理函数。所以不会打印regular,而是打印special。

4.2 路由级别中间件

router.js

const express = require('express');

// 1.创建路由实例
const router = express.Router();

// 2. 配置路由
router.get('/aaa', (req, res) => {
  res.send('get /aaa');
})

router.post('/bbb', (req, res) => {
  res.send('post /bbb');
})

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

// 4. 将路由挂载(集成)到Express实例应用中(见app.js)

app.js

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

const router = require('./router.js');

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

// 4. 将路由挂载(集成)到Express实例应用中
app.use('/abc', router);		// 给路由限定访问前缀/abc

app.listen(3000, () => {
  console.log('http://localhost:3000/');
})

路由级别中间件

链式路由处理程序

app.route('/abc')
  .get((req, res) => {
    res.send('get');
  })
  .post((req, res) => {
    res.send('post');
  })

4.3 错误处理中间件

app.use((err, req, res, next) => {   // 四个参数都要有才是错误处理中间件。如果只有err、req、res,则err实际上是req对象
  console.log('错误: ', err);
  res.status(500).json({
    error: err.message
  })
})

四个参数都要有才是错误处理中间件。如果只有err、req、res,则err实际上是req对象

app.js

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

const router = require('./router.js');

app.use(router);

app.use((err, req, res, next) => {   // 四个参数都要有才是错误处理中间件。如果只有err、req、res,则err实际上是req对象
  console.log('错误: ', err);
  res.status(500).json({
    error: err.message
  })
})

app.listen(3000, () => {
  console.log('http://localhost:3000/');
})

router.js

const express = require('express');

// 1.创建路由实例
const router = express.Router();

// 2. 配置路由
router.get('/', (req, res, next) => {
  try {
    const d = b + 1;
  } catch (err) {
    next(err);  // 跳过所有剩余的无错误处理路由和中间件函数
  }
})

router.get('/', (req, res, next) => {
  console.log('第二个路由处理函数');
  res.end();
})

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

// 4. 将路由挂载(集成)到Express实例应用中

image-20220210103104627

4.4 内置中间件

  • express.json():解析Content-Type为application/json格式的请求体
  • express.urlencoded():解析Content-Type为application/x-www-form-urlencoded格式的请求体
  • express.raw():解析Content-Type为application/octet-stream格式的请求体
  • express.text():解析Content-Type为text/plain格式的请求体
  • express.static():托管静态资源文件

4.5 第三方中间件

Express middleware

使用示例:morgan日志中间件

  1. npm install morgan

  2. const express = require('express');
    const morgan = require('morgan');   // 1. 引入
    
    const app = express();
    
    app.use(morgan('tiny'));      // 2. 挂载
    
    app.get('/', (req, res) => {
      res.send('Hello World!');
    })
    
    app.listen(3000, () => {
      console.log('http://localhost:3000/');
    })
    
  3. 每次请求都会打印出请求日志

    image-20220210105212413

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值