思考🤔:什么是中间件?
中间件,对应的英语叫做“middleware”,是一种在计算机程序或系统中间起桥梁作用的软件层,通常用于连接不同的组件、处理逻辑、或者在输入和输出之间执行某种操作。中间件在不同的领域和上下文中可能有稍微不同的含义,但核心概念一致:对数据流进行中间处理。
聚焦到 Web 开发中,中间件最常见的就是服务器处理请求时的一段逻辑代码,介于客户端请求和响应之间,用于:
- 请求过的时候可以修改请求对象(req)
- 响应返回的时候可以修改响应对象(res)
- 控制是否将请求传递给下一个中间件或终止请求
使用中间件可以做到:
- 日志记录
- 权限控制
- 请求解析
- 错误处理
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 中,中间件分为三类:
-
匿名中间件:又被称之为内联中间件,直接在页面中定义的
<template><div>只有登录用户才能访问此页面。</div></template><script setup>definePageMeta({middleware: async (context) => {const { $auth } = useNuxtApp()if (!$auth.isLoggedIn) {return navigateTo('/login')}},})</script> -
命名路由中间件: 放置于 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> -
全局路由中间件: 同样是放置于 middleware 目录下面,以 .global 后缀结尾,每次路由发生成改变的时候,都会执行。相当于 Vue-router 里面的全局守卫。
~/middleware/logger.global.ts export default defineNuxtRouteMiddleware((to, from) => {console.log(`Navigating from ${from.fullPath} to ${to.fullPath}`)})
如果涉及到多个中间件,基本顺序如下:
- 全局中间件:每次路由切换的时候,都会执行
- 页面定义的中间件,按顺序(如果使用数组语法声明了多个中间件)执行
第一次页面加载的时候,中间件会在服务端以及客户端都执行一次,之后应用变为了一个单页应用,所以就只在客户端执行。
关于全局中间件的顺序,按照的是 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 的中间件内,做了一层封装,通过返回值来决定是否放行。
返回值的情况有:
- 无返回值:不阻止导航,将继续执行下一个中间件函数(如果有的话),或者完成路由导航(就相当于 Vue-router 导航守卫中的 next( ) )
return navigateTo('/'):重定向到给定的路径,并在服务器端发生重定向时设置重定向代码为 302(相当于 next(’/’) )return navigateTo('/' , { redirectCode: 301 }):重定向到给定的路径,并在服务器端发生重定向时设置重定向代码为 301return abortNavigation( ):停止当前的导航return abortNavigation(error):停止当前的导航,并且提供错误信息
课堂练习
假设我们正在开发一个后台管理系统,其中有以下用户角色:
- guest:只能访问公开页面(仪表盘)
- editor:只能访问某些特定页面(编辑器、仪表盘)
- admin:可以访问所有页面
-EOF-