middleware
Maschinelle Übersetzung ·0 % geprüft
Nuxt 提供了一个可自定义的 路由中间件 框架,您可以在整个应用程序中使用,适合提取您希望在导航到特定路由之前运行的代码。
路由中间件有三种类型:
- 匿名(或内联)路由中间件,直接在页面内定义。
- 命名路由中间件,放置在
middleware/目录下,并在页面使用时通过异步导入自动加载。 - 全局路由中间件,放置在带有
.global后缀的middleware/目录下,会在每次路由变更时执行。
前两种路由中间件可以在 definePageMeta 中定义。
myMiddleware 变成 my-middleware。用法
路由中间件是导航守卫,接收当前路由和目标路由作为参数。
export default defineNuxtRouteMiddleware((to, from) => {
if (to.params.id === '1') {
return abortNavigation()
}
// 在实际应用中,可能不会把每个路由都重定向到 `/`
// 但是在重定向之前检查 `to.path` 是很重要的,否则可能会导致无限重定向循环
if (to.path !== '/') {
return navigateTo('/')
}
})Nuxt 提供了两个全局辅助函数,可以直接从中间件返回使用。
navigateTo- 重定向到给定路由abortNavigation- 中止导航,可选地附带错误消息。
与 vue-router 的导航守卫不同,中间件不会传入第三个 next() 参数,重定向或取消路由通过返回值处理。
可能的返回值包括:
- 什么都不返回(简单的
return或没有返回)- 不阻塞导航,将执行下一个中间件(如果有)或完成路由导航 return navigateTo('/')- 重定向到指定路径,若在服务器端执行重定向,则状态码为302Foundreturn navigateTo('/', { redirectCode: 301 })- 重定向到指定路径,若在服务器端执行重定向,则状态码为301Moved Permanentlyreturn abortNavigation()- 停止当前导航return abortNavigation(error)- 拒绝当前导航,并带有错误
中间件执行顺序
中间件的执行顺序为:
- 全局中间件
- 页面定义的中间件顺序(若使用数组语法声明多个中间件)
例如,假设您有如下中间件和组件:
-| middleware/
---| analytics.global.ts
---| setup.global.ts
---| auth.ts<script setup lang="ts">
definePageMeta({
middleware: [
function (to, from) {
// 自定义内联中间件
},
'auth',
],
})
</script>您可以预计中间件执行顺序为:
analytics.global.tssetup.global.ts- 自定义内联中间件
auth.ts
全局中间件排序
默认情况下,全局中间件按文件名的字母顺序执行。
但有时您可能需要指定执行顺序。例如,在上述场景中,可能需要 setup.global.ts 在 analytics.global.ts 之前执行。这时建议给全局中间件文件名添加“字母顺序”数字前缀。
-| middleware/
---| 01.setup.global.ts
---| 02.analytics.global.ts
---| auth.ts10.new.global.ts 会排在 2.new.global.ts 之前。这就是示例中单数字前缀带 0 的原因。中间件何时运行
如果您的站点是服务端渲染或静态生成,中间件会在页面首次渲染时执行,然后在客户端再执行一次。如果中间件依赖于浏览器环境(如生成的站点,或缓存响应,或要读取本地存储),这很有用。
但若您想避免此行为,可以这样写:
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
}
})即便您在服务器端中间件中抛出了错误并渲染了错误页,浏览器端仍会再次执行该中间件。
useError 检查是否正在处理错误。动态添加中间件
始终在中间件中使用 to 和 from 参数来访问目标路由和前一个路由。完全避免在此上下文中使用 useRoute() 组合式函数。
中间件中没有“当前路由”的概念,因为中间件可以中止导航或重定向到其他路由。在此上下文中,useRoute() 组合式函数始终会返回不准确的信息。
useRoute() 的组合式函数,即使中间件中没有直接调用它,也可能触发此警告。
这会导致与上述相同的问题,因此在中间件中使用这些函数时,您应该调整函数结构,让它们接受路由作为参数。// @errors: 2304
export default defineNuxtRouteMiddleware((to) => {
// die Route an die Funktion übergeben, um den Aufruf von `useRoute()` in Middleware zu vermeiden
doSomethingWithRoute(to)
// ❌ Das gibt eine Warnung aus und wird NICHT empfohlen
callsRouteInternally()
})// die Route als Argument übergeben, damit sie in Middleware korrekt verwendet werden kann
export function doSomethingWithRoute (route = useRoute()) {
// ...
}// ❌ Diese Funktion eignet sich nicht für die Verwendung in Middleware
export function callsRouteInternally () {
const route = useRoute()
// ...
}动态添加中间件
您可以使用 addRouteMiddleware() 辅助函数手动添加全局或命名路由中间件,例如在插件中添加。
export default defineNuxtPlugin(() => {
addRouteMiddleware('global-test', () => {
console.log('此全局中间件是在插件中添加的,将在每次路由变更时运行')
}, { global: true })
addRouteMiddleware('named-test', () => {
console.log('此命名中间件是在插件中添加的,会覆盖同名已存在中间件')
})
})示例
-| middleware/
---| auth.ts在页面文件中,您可以引用该路由中间件:
<script setup lang="ts">
definePageMeta({
middleware: ["auth"]
// 或者 middleware: 'auth'
})
</script>导航到该页面前,将执行 auth 路由中间件。
在构建时设置中间件
您可以不在每个页面中使用 definePageMeta,而是在 pages:extend 钩子中添加命名路由中间件。
import type { NuxtPage } from 'nuxt/schema'
export default defineNuxtConfig({
hooks: {
'pages:extend' (pages) {
function setMiddleware (pages: NuxtPage[]) {
for (const page of pages) {
if (/* 某些条件 */ true) {
page.meta ||= {}
// 注意,这会覆盖页面中 `definePageMeta` 里设置的中间件
page.meta.middleware = ['named']
}
if (page.children) {
setMiddleware(page.children)
}
}
}
setMiddleware(pages)
},
},
})