Nuxt Nation 大会即将到来。加入我们,时间为 11 月 12 日至 13 日。

中间件

Nuxt 提供中间件,用于在导航到特定路由之前运行代码。

Nuxt 提供了一个可自定义的**路由中间件**框架,您可以在整个应用程序中使用它,非常适合提取您希望在导航到特定路由之前运行的代码。

路由中间件有三种类型

  1. 匿名(或内联)路由中间件直接在页面中定义。
  2. 命名路由中间件,放置在middleware/中,并在页面上使用时通过异步导入自动加载。
  3. 全局路由中间件,放置在middleware/中,并带有.global后缀,并在每次路由更改时运行。

前两种路由中间件可以在definePageMeta中定义。

中间件名称规范化为 kebab-case:myMiddleware变为my-middleware
路由中间件在 Nuxt 应用的 Vue 部分运行。尽管名称相似,但它们与服务器中间件完全不同,服务器中间件在应用的 Nitro 服务器部分运行。

用法

路由中间件是导航守卫,接收当前路由和下一个路由作为参数。

middleware/my-middleware.ts
export default 
defineNuxtRouteMiddleware
((
to
,
from
) => {
if (
to
.
params
.
id
=== '1') {
return
abortNavigation
()
} // In a real app you would probably not redirect every route to `/` // however it is important to check `to.path` before redirecting or you // might get an infinite redirect loop if (
to
.
path
!== '/') {
return
navigateTo
('/')
} })

Nuxt 提供两个全局可用的辅助函数,可以直接从中间件返回。

  1. navigateTo - 重定向到给定路由
  2. abortNavigation - 中断导航,并带有一个可选的错误消息。

vue-router导航守卫不同,不会传递第三个next()参数,并且**通过从中间件返回值来处理重定向或路由取消**。

可能的返回值是

  • nothing(一个简单的return或根本没有返回值) - 不阻止导航,并将移动到下一个中间件函数(如果有),或完成路由导航
  • return navigateTo('/') - 重定向到给定路径,如果重定向发生在服务器端,则将重定向代码设置为302 Found
  • return navigateTo('/', { redirectCode: 301 }) - 重定向到给定路径,如果重定向发生在服务器端,则将重定向代码设置为301 Moved Permanently
  • return abortNavigation() - 停止当前导航
  • return abortNavigation(error) - 使用错误拒绝当前导航
文档 > API > 实用程序 > 导航到中了解更多信息。
文档 > API > 实用程序 > 中断导航中了解更多信息。
我们建议使用上述辅助函数执行重定向或停止导航。vue-router 文档中描述的其他可能的返回值可能有效,但在将来可能会发生重大更改。

中间件顺序

中间件按以下顺序运行

  1. 全局中间件
  2. 页面定义的中间件顺序(如果使用数组语法声明了多个中间件)

例如,假设您有以下中间件和组件

middleware/ 目录
-| middleware/
---| analytics.global.ts
---| setup.global.ts
---| auth.ts
pages/profile.vue
<script setup lang="ts">
definePageMeta({
  middleware: [
    function (to, from) {
      // Custom inline middleware
    },
    'auth',
  ],
});
</script>

您可以预期中间件按以下顺序运行

  1. analytics.global.ts
  2. setup.global.ts
  3. 自定义内联中间件
  4. auth.ts

全局中间件排序

默认情况下,全局中间件根据文件名按字母顺序执行。

但是,在某些情况下,您可能希望定义特定顺序。例如,在最后一个场景中,setup.global.ts可能需要在analytics.global.ts之前运行。在这种情况下,我们建议在全局中间件前面加上“字母”编号。

目录结构
-| middleware/
---| 01.setup.global.ts
---| 02.analytics.global.ts
---| auth.ts
如果您不熟悉“字母”编号,请记住文件名按字符串排序,而不是按数字值排序。例如,10.new.global.ts将出现在2.new.global.ts之前。这就是示例在一位数前面加上0的原因。

中间件何时运行

如果您的站点是服务器渲染或生成的,则初始页面的中间件将在渲染页面时以及在客户端再次执行。如果您的中间件需要浏览器环境,例如如果您有一个生成的站点,积极缓存响应或想要从本地存储读取值,则可能需要这样做。

但是,如果您想避免此行为,您可以这样做

middleware/example.ts
export default 
defineNuxtRouteMiddleware
(
to
=> {
// skip middleware on server if (import.meta.
server
) return
// skip middleware on client side entirely if (import.meta.
client
) return
// or only skip middleware on initial client load const
nuxtApp
=
useNuxtApp
()
if (import.meta.
client
&&
nuxtApp
.
isHydrating
&&
nuxtApp
.
payload
.
serverRendered
) return
})
渲染错误页面是一个完全独立的页面加载,这意味着任何注册的中间件都将再次运行。您可以使用useError在中间件中检查是否正在处理错误。

动态添加中间件

可以使用addRouteMiddleware()辅助函数(例如从插件中)手动添加全局或命名路由中间件。

export default 
defineNuxtPlugin
(() => {
addRouteMiddleware
('global-test', () => {
console
.
log
('this global middleware was added in a plugin and will be run on every route change')
}, {
global
: true })
addRouteMiddleware
('named-test', () => {
console
.
log
('this named middleware was added in a plugin and would override any existing middleware of the same name')
}) })

示例

目录结构
-| middleware/
---| auth.ts

在您的页面文件中,您可以引用此路由中间件

<script setup lang="ts">
definePageMeta({
  middleware: ["auth"]
  // or middleware: 'auth'
})
</script>

现在,在导航到该页面之前,将运行auth路由中间件。

文档 > 示例 > 路由 > 中间件中阅读和编辑实时示例。

在构建时设置中间件

无需在每个页面上使用definePageMeta,您可以在pages:extend钩子中添加命名路由中间件。

nuxt.config.ts
import type { 
NuxtPage
} from 'nuxt/schema'
export default
defineNuxtConfig
({
hooks
: {
'pages:extend' (
pages
) {
function
setMiddleware
(
pages
:
NuxtPage
[]) {
for (const
page
of
pages
) {
if (/* some condition */ true) {
page
.
meta
||= {}
// Note that this will override any middleware set in `definePageMeta` in the page
page
.
meta
.middleware = ['named']
} if (
page
.
children
) {
setMiddleware
(
page
.
children
)
} } }
setMiddleware
(
pages
)
} } })