Skip to content

中间件

思考🤔:什么是中间件?

中间件,对应的英语叫做“middleware”,是一种在计算机程序或系统中间起桥梁作用的软件层,通常用于连接不同的组件、处理逻辑、或者在输入和输出之间执行某种操作。中间件在不同的领域和上下文中可能有稍微不同的含义,但核心概念一致:对数据流进行中间处理

聚焦到 Web 开发中,中间件最常见的就是服务器处理请求时的一段逻辑代码,介于客户端请求和响应之间,用于:

使用中间件可以做到:

Express:

const express = require('express')
const app = express()
// 使用中间件
app.use((req, res, next) => {
console.log(`Request URL: ${req.url}`)
next() // 控制是否放行
})
app.get('/', (req, res) => {
res.send('Hello, Middleware!')
})
app.listen(3000, () => console.log('Server is running on port 3000'))

其实 Vue-router 中的导航守卫,其实就是一种中间件的实现。

中间件细节#

中间件分类与顺序

在 Nuxt 中,中间件分为三类:

  1. 匿名中间件:又被称之为内联中间件,直接在页面中定义的

    <template>
    <div>只有登录用户才能访问此页面。</div>
    </template>
    <script setup>
    definePageMeta({
    middleware: async (context) => {
    const { $auth } = useNuxtApp()
    if (!$auth.isLoggedIn) {
    return navigateTo('/login')
    }
    },
    })
    </script>
  2. 命名路由中间件: 放置于 middleware 目录下面

    ~/middleware/auth.ts
    export default defineNuxtRouteMiddleware((to, from) => {
    const { $auth } = useNuxtApp()
    if (!$auth.isLoggedIn) {
    return navigateTo('/login')
    }
    })

    页面中引入

    <template>
    <div>只有登录用户才能访问此页面。</div>
    </template>
    <script setup>
    definePageMeta({
    middleware: ['auth'],
    })
    </script>
  3. 全局路由中间件: 同样是放置于 middleware 目录下面,以 .global 后缀结尾,每次路由发生成改变的时候,都会执行。相当于 Vue-router 里面的全局守卫。

    ~/middleware/logger.global.ts
    export default defineNuxtRouteMiddleware((to, from) => {
    console.log(`Navigating from ${from.fullPath} to ${to.fullPath}`)
    })

如果涉及到多个中间件,基本顺序如下:

  1. 全局中间件:每次路由切换的时候,都会执行
  2. 页面定义的中间件,按顺序(如果使用数组语法声明了多个中间件)执行

第一次页面加载的时候,中间件会在服务端以及客户端都执行一次,之后应用变为了一个单页应用,所以就只在客户端执行。

关于全局中间件的顺序,按照的是 ASCII 的顺序来执行的。如果期望 setup 全局中间件先执行,需要修改中间件名字:

middleware/
--| 01.setup.global.ts
--| 02.analytics.global.ts

指定中间件执行时机

在 SSR 渲染时,默认情况下中间件会在服务器端和客户端各执行一次。可以对环境进行判断,在期望的环境下执行。

export default defineNuxtRouteMiddleware((to) => {
// 在服务器端跳过中间件
if (import.meta.server) return
// 完全在客户端跳过中间件
if (import.meta.client) return
// 或仅在初始客户端加载时跳过中间件
const nuxtApp = useNuxtApp()
if (
import.meta.client &&
nuxtApp.isHydrating &&
nuxtApp.payload.serverRendered
)
return
})

中间件参数与返回值

接下来看一下中间件本身的一些内容。首先是参数:

export default defineNuxtRouteMiddleware((to, from) => {
// ...
})

在回调函数中,会自动传入两个参数:to、from

Vue-router 的导航守卫中,也有 to、from,但是还会多一个 next,Nuxt 的中间件的参数里面没有 next 这个参数。在 Nuxt 的中间件内,做了一层封装,通过返回值来决定是否放行。

返回值的情况有:

  1. 无返回值:不阻止导航,将继续执行下一个中间件函数(如果有的话),或者完成路由导航(就相当于 Vue-router 导航守卫中的 next( ) )
  2. return navigateTo('/') :重定向到给定的路径,并在服务器端发生重定向时设置重定向代码为 302(相当于 next(’/’) )
  3. return navigateTo('/' , { redirectCode: 301 }) :重定向到给定的路径,并在服务器端发生重定向时设置重定向代码为 301
  4. return abortNavigation( ):停止当前的导航
  5. return abortNavigation(error):停止当前的导航,并且提供错误信息

课堂练习

假设我们正在开发一个后台管理系统,其中有以下用户角色:


-EOF-