Node: Express的中间件的使用

一、简介

Express框架为开发者提供了一个中间件功能,这个中间件在服务的请求-响应过程提供一个可以修改内容的机会。中间件的完整结构是这样的,它必须是一个函数,可以访问的参数有错误对象err、请求对象req、响应对象res、以及另一个中间件next函数。next函数的作用是可以将当前中间件的控制权进行转交向下传递。大致结构如下:

// 中间件完整的结构
// 1、是一个函数
// 2、可选参数:err、req、res、 next, 注意:err/req/res均为对象、 next为函数,也是下一个中间件
function middleware(err, req, res, next) {
    //中间件负责的工作可以包括以下几种:
    //1、异常处理
    //2、功能函数,处理一下业务功能,然后转交控制权
    //3、响应请求----->结束响应----->当做路由的处理函数
}

 

二、应用

对中间件结构有了初步了解后,现在可以简单使用一下中间件这个功能。例如,对所有发送的HTTP请求,验证其参数的合法性。如果验证成功,则继续后续的请求操作。代码如下:

//导入express框架
const express = require('express');

//创建express服务实例
const app = express();

//定义一个验证参数的中间件
function valid_name_middleware(req, res, next)  {
    let {name} = req.query;
    if (!name || !name.length) {
        res.json({
            message:'缺少name参数'
        })
    }else{
        next(); //转交控制权
    }
}

//1、这里首先会验证所有的HTTP请求
app.all('*', valid_name_middleware);

//2、如果合法,接着才会进行get请求
app.get('/demo', (req, res) => {
    res.json({
        message: 'response success for demo'
    })
})

//监听
app.listen(3000, ()=>{
    console.log('服务器启动了!');
});

 

三、类型

1、应用级别的中间件

在全局作用域上起作用,处于最顶层结构上,在app实例化时就立马注册使用它。使用app.use----api去加载。

//导入express框架
const express = require('express');

//创建express服务实例
const app = express();

//自定义一个logger中间件
function logger_middleware(req, res, next) {
    console.log('请求来了!');
    next();
}

//注册到app全局的级别上
app.use(logger_middleware);

//监听
app.listen(3000, ()=>{
    console.log('服务器启动了!');
});
//终端结果如下:
[nodemon] restarting due to changes...
[nodemon] starting `node src/app.js`
服务器启动了!
请求来了! 

2、系统内置的中间件

express.static是express内置的中间件之一,基于serve-static,它负责处理应用中的静态资源的。还有express.json()express.static()express.Router()express.urlencoded()

//导入express框架
const express = require('express');

//创建express服务实例
const app = express();

//加载一个 public 的中间件
//express.static(root, [options]):参数 root 指提供静态资源的根目录路径
//可选的 options 参数可参考官方文档:http://www.expressjs.com.cn/4x/api.html#express.static
app.use(express.static('public',{

}))

//监听
app.listen(3000, ()=>{
    console.log('服务器启动了!');
});

3、第三方提供中间件

cookie-parser和multiparty都是第三方提供的中间件,cookie-parser是用来解析cookie的,multiparty则是用来进行表单或图片等资源上传的。

//导入express框架
const express = require('express');

//创建express服务实例
const app = express();

//加载第三方解析cookie的中间件:cookie-parser
//先安装"cookie-parser":  npm install cookie-parser -D
//然后使用use加载 cookie 解析中间件
var cookieParser = require('cookie-parser');
app.use(cookieParser());

//加载第三方上传资源的中间件:multiparty
//先安装"multiparty":  npm install multiparty -D
const multiparty = require('multiparty');
app.post('/upload', (req, res) => {
    let form = new multiparty.Form()
    form.uploadDir = './images';//指定图片的文件夹
    form.parse(req,function(err,fields,files){
       //获取提交的数据以及图片上传成功返回的图片信息 field是表单数据,files为图片信息
    })
})

//监听
app.listen(3000, ()=>{
    console.log('服务器启动了!');
});

4、路由级别的中间件

在前面介绍路由时,对路由进行拆分后统一到应用顶层进行注册时,用到的方式就是将路由作为中间件使用。也是使用use()函数。

//导入express框架
const express = require('express');

//创建express服务实例
const app = express();

//导入路由
const userRouter = require('./user.router')

//注册路由,将路由当做中间件,放在应用级别上
app.use(userRouter);

//也可以给userRouter配一个父级别的路由, 相当于起了一个命令空间的作用
app.use('/user', userRouter);

//此时,访问"http://127.0.0.1:3000/information" 和 "http://127.0.0.1:3000/user/information"都可以请求成功

//监听
app.listen(3000, ()=>{
    console.log('服务器启动了!');
});

上面的路由作为中间件放在了应用级别上,此时还可以在路由内部定义中间件,需要修改user.router.js文件如下:

//导入express框架
const express = require('express');

//定义一个路由
const router = express.Router();

/*

//第一个场景:在路由内部定义一个中间件
router.use(function(req, res, next){
    console.log('logger from inner router');
    next();
})
//发起get请求
router.get('/information', (req, res) => {
    res.json({
        message:"from router user !"
    })    
})

*/

//第二个场景:针对单个路由,支持中间件栈,也就是一个数组,依次执行
function valid_login_parms_middleware(req, res, next) {
    let{username, password} = req.query;
    if (!username || !password) {
        res.json({
            message:"参数校验失败!"
        })
    }
    else{
        //将内容传递给next
        req.result = {
            username,
            password
        }
        next(); //转交控制权
    }
}
//发起get请求
//第2个参数是数组,可以放很多个中间件,依次执行
router.get('/login', [valid_login_parms_middleware], (req, res) => {
    let {result} = req;
    res.json({
        result,
        message:"from router user ! login success!"
    })    
})


//将路由暴露出来
module.exports = router;

第一种场景Postman运行的结果还是一样,不过在get请求响应之前,路由内部定义的中间件会先执行,然后由next函数转交控制权给get请求。

//终端结果如下:
[nodemon] restarting due to changes...
[nodemon] starting `node src/app.js`
服务器启动了!
logger from inner router

第二个场景Postman运行的结果如下:

 5、异常处理的中间件

中间件的参数中有一个err对象可以访问,因此,开发者可以定制一个处理异常的中间件,将请求错误的日志可视化展现出来,提高开发效率。注意,处理异常的中间件必须注册到所有路由的底部,这样才能监听异常。

//导入express框架
const express = require('express');

//创建express服务实例
const app = express();

//发送一个get请求,抛出异常
app.get('/user', (req, res) => {
    throw new Error('测试接口异常!')
})

//监听
app.listen(3000, ()=>{
    console.log('服务器启动了!');
}); 

这个方式抛出的这个日志很复杂,非常不利于查找原因,截图如下:

此时修改这个文件,定制一个异常处理的中间件,此时抛出来的日志相当明显,非常清新,修改和截图如下:

//导入express框架
const express = require('express');

//创建express服务实例
const app = express();

//发送一个get请求
app.get('/user', (req, res) => {
    throw new Error('测试接口异常!')
})

//定义一个异常处理的中间件
function error_handle_middleware(err, req, res, next) {
    let {message} = err;
    if (err) {
        res.status(500)
        res.json({
            message:`${message || '服务器异常'}`
        })
    }else{
        //    
    }
}

//err为空时,这个是最后处理不了一般的错误时,报404。
function not_found_handler(err, res, next) {
    res.json({
        message:'api不存在!'
    })
}

app.use(error_handle_middleware);
app.use(not_found_handler);

//监听
app.listen(3000, ()=>{
    console.log('服务器启动了!');
});

 

posted @ 2019-12-30 17:33  XYQ全哥  阅读(320)  评论(0编辑  收藏  举报