9.中间件分类

128 阅读3分钟

中间件分类

在Express中应用程序可以使用以下类型的中间件:

  • 应用程序级别中间件
  • 路由级别中间件
  • 错误处理中间件
  • 内置中间件
  • 第三方中间件

1. 应用程序级别中间件

  • 不关心请求路径
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.methods)
    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) {
    res.send('User info')
})
  • 为同一个路径定义多个处理中间件:
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)
})
  • 中间件在数组中声明为可重用
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')
})

要从路由器中间件堆栈中跳过其余中间件功能,请调用next('route')将控制权传递给下一个路由。 注意:next('route')仅在使用app.MRTHOD()router.METHOD()函数加载的中间件函数中有效。

2.路由器级中间件

路由器级中间件与应用程序级中间件的工作方式相同,只不过它绑定到的实例express.Router()

var router = express.Router() 使用router.use()router.METHOD()函数加载路由器级中间件

新建router.js,代码如下:

const express = require('express');
const { getDb, saveDb } = require('./db')
// 1.创建路由实例
// 路由实例其实就相当于一个mini Express实例
const router = express.Router()

// 2.配置路由
// 查询任务
router.get('/', async (req, res) => {
    try {
        let db = await getDb();
        res.status(200).json(db.todos);
    } catch (err) {
        res.status(500).json({
            error: err.message
        })
    }
})
// 查询单个任务
router.get('/:id', async (req, res) => {
    try {
        let db = await getDb();
        let todo = db.todos.find(todo => todo.id.toString() === req.params.id);
        if (!todo) {
            return res.status(404).json({
                data: 'not found'
            })
        }
        res.status(200).json(todo)
    } catch {
        res.status(500).json({
            error: err.message
        })
    }
})
// 添加任务
router.post('/', async (req, res) => {
    try {
        // 1. 获取请求体数据
        const todo = req.body;

        // 2. 验证数据
        if (!todo.name) {
            return res.status(422).json({
                error: 'The file name is required!!'
            })
        }
        // 3。验证通过,将数据存储到db中
        const db = await getDb();
        const lastTodo = db.todos[db.todos.length - 1];
        todo.id = lastTodo ? lastTodo.id + 1 : 1;
        db.todos.push(todo)
        await saveDb(db)
        res.status(200).json(todo)
    } catch (err) {
        res.status(500).json({
            error: err.message
        })
    }
})
// 修改任务
router.patch('/:id', async (req, res) => {
    try {
        const id = req.params.id;
        const todo = req.body;
        if (!todo.name) {
            return res.status(422).json({
                error: 'The todo name is required!!'
            })
        }
        let db = await getDb()
        db.todos.forEach(item => {
            if (item.id == id) {
                item.name = todo.name
            }
        });
        await saveDb(db)
        res.status(200).json({
            data: '修改成功'
        })
    } catch (err) {
        res.status(500).json({
            error: err.message
        })
    }
})
// 删除任务
router.delete('/:id', (req, res) => {
    res.send(`delete /todos/${req.params.id}`)
})

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

// 4.将路由怪哉集成到Express实例应用当中


index.js,代码如下:

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

const router = require('./router')

//配置解析表单请求体: ‘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 is running!!')
})

3.错误处理级中间件

错误处理中间件必须要定义四个参数,缺一不可。

app.use((err, req, res, next) => {
    res.status(500).json({
        error: err.message
    })
})

如果将任何内容传递给该next()函数(字符串除外‘route’),Express都会将当前请求视为错误,并且将跳过所有剩余的非错误处理路由和中间件函数。 修改之后的代码如下:

router.get('/', async (req, res) => {
    try {
        let db = await getDb();
        res.status(200).json(db.todos);
    } catch (err) {
        // res.status(500).json({
        //     error: err.message
        // })
        next(err)
    }
})

404异常处理中间件,代码如下:

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

const router = require('./router')

//配置解析表单请求体: ‘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.')
})

app.use((err, req, res, next) => {
    res.status(500).json({
        error: err.message
    })
})

app.listen(3000, () => {
    console.log('server is running!!')
})

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() 托管静态资源文件

5.第三方中间件

包括官方的和第三方的中间件,查看官网。