11. 示例 [nuxt-08]:路由中间件
在本示例中,我们将介绍路由中间件的概念,即每当路由发生变化时执行的脚本。
示例 [nuxt-08] 最初是通过克隆 [nuxt-01] 项目创建的:

路由中间件必须放置在名为 [middleware] 的文件夹中 [2]。可以实现两级路由:
- 适用于每次导航的路由。此类路由需在 [nuxt.config.js] 文件中声明;
- 仅当特定页面作为路由目标时才对其应用的路由。此类路由需在该目标页面中进行声明;
11.1. 通用路由
[middleware/routing.js] 文件将处理通用路由。它在 [nuxt.config.js] 文件中声明如下:
router: {
base: '/nuxt-08/',
middleware: ['routing']
},
通用路由中间件是路由器的属性(第 1 行)。可以包含多个路由中间件组件。因此,在第 3 行中,[middleware] 属性的值是一个数组。请注意,我们不使用路径来指定中间件。系统会自动在项目的 [middleware] 文件夹中搜索中间件;
[routing] 中间件仅在此处进行日志记录:
/* eslint-disable no-undef */
/* eslint-disable no-console */
export default function(...args) {
// who executes this code?
console.log('[routing], process.server=', process.server, 'process.client=', process.client)
const who = process.server ? 'server' : 'client'
const routing = '[routing ' + who + ']'
// number of arguments
console.log(routing + ', il y a', args.length, 'argument(s)')
// 1st argument
const context = args[0]
// key context
dumpkeys(routing + ', context', context)
// the application
dumpkeys(routing + ', context.app', context.app)
// the road
dumpkeys(routing + ', context.route', context.route)
console.log(routing + ', context.route=', context.route)
// the router
dumpkeys(routing + ', context.app.router', context.app.router)
// on router.options.routes
dumpkeys(routing + ', context.app.router.options.routes', context.app.router.options.routes)
console.log(routing + ', context.app.router.options.routes=', context.app.router.options.routes)
}
function dumpkeys(message, object) {
// list of [object] keys
const ligne = 'Liste des clés [' + message + ']'
console.log(ligne)
// kEY LIST
if (object) {
console.log(Object.keys(object))
}
}
- 第 3 行:我们将看到中间件接收了一个参数:执行器的上下文(服务器或客户端);
- 第 4–25 行:我们显示各种对象的属性以确定哪些可用。我们会发现中间件上下文与插件上下文几乎完全相同;
11.2. 特定页面的路由
我们希望控制用户访问 [index] 页面的路径。为此,我们需要向该 [index] 页面添加 [middleware] 属性:
<script>
/* eslint-disable no-undef */
/* eslint-disable no-console */
/* eslint-disable nuxt/no-env-in-hooks */
import Navigation from '@/components/navigation'
import Layout from '@/components/layout'
export default {
name: 'Home',
// components used
components: {
Layout,
Navigation
},
// life cycle
beforeCreate() {
// client and server
console.log('[home beforeCreate]')
},
created() {
// client and server
console.log('[home created]')
},
beforeMount() {
// customer only
console.log('[home beforeMount]')
},
mounted() {
// customer only
console.log('[home mounted]')
},
// routing
middleware: ['index-routing']
}
</script>
- 第 34 行:[middleware] 属性列出了在显示下一页为 [index] 页面时将执行的脚本。同样,这些脚本将在项目的 [middleware] 文件夹中进行搜索;
[index-routing] 中间件如下所示:
/* eslint-disable no-undef */
/* eslint-disable no-console */
export default function(...args) {
// who executes this code?
console.log('[index-routing], process.server=', process.server, 'process.client=', process.client)
const who = process.server ? 'server' : 'client'
const indexRouting = '[index-routing ' + who + ']'
// number of arguments
console.log(indexRouting + ', il y a', args.length, 'argument(s)')
// 1st argument
const context = args[0]
// key context
dumpkeys(indexRouting + ', context', context)
// the application
dumpkeys(indexRouting + ', context.app', context.app)
// the road
dumpkeys(indexRouting + ', context.route', context.route)
console.log(indexRouting + ', context.route=', context.route)
// the router
dumpkeys(indexRouting + ', context.app.router', context.app.router)
// on router.options.routes
dumpkeys(indexRouting + ', context.app.router.options.routes', context.app.router.options.routes)
console.log(indexRouting + ', context.app.router.options.routes=', context.app.router.options.routes)
// where do we come from?
if (context.from) {
console.log('from=', context.from)
}
}
function dumpkeys(message, object) {
// list of [object] keys
const ligne = 'Liste des clés [' + message + ']'
console.log(ligne)
// kEY LIST
if (object) {
console.log(Object.keys(object))
}
}
[index-routing] 的代码与 [routing] 完全相同,且产生相同的结果。我们感兴趣的是观察这两个中间件何时被执行。
11.3. 运行项目
我们运行该项目。日志如下:
服务器首先执行 [routing] 脚本:
这与我们使用插件时得到的结果相同。
- 第 15 行:[redirect] 属性常用于中间件;它允许你更改当前路由的目标;
随后,由于要显示的页面是 [index] 页面,服务器会执行 [index-routing] 脚本并显示以下日志:
使用 [index-routing] 脚本获得的结果与使用 [routing] 脚本获得的结果相似。
一旦客户端浏览器接收到 [index] 页面,客户端脚本便接管处理。日志内容如下:
因此,我们可以看到,当应用程序启动时,客户端不会执行任何中间件。这意味着,每当用户向服务器发起请求时,都会发生这种情况。只有在客户端内部导航时,客户端才会执行中间件。例如,让我们使用 [Page 1] 链接导航到 [page1] 页面(我们当前位于 [index] 页面)。此时日志如下:
- 第 2 行:[routing] 中间件由客户端执行;
- 第 4 行:注意 [from] 属性:这是我们来自的路线;
- 第 9 行:[context.route] 是我们要前往的路由;
- 第 15–18 行:显示 [page1] 页面;
现在,让我们通过 [Home] 链接返回 [index] 页面。此时日志如下:
- 第 1-15 行:客户端执行 [routing] 中间件。这是正常现象。每次路由发生变化时都会执行该中间件;
- 第 16–29 行:客户端执行 [index-routing] 中间件,因为:
- [index] 是当前路由的目标(参见第 23 行);
- [index] 页面已定义了一个名为 [index-routing] 的中间件;
由此可见,客户端会在执行页面关联的中间件之前,先执行通用路由中间件。