Skip to content

11. Beispiel [nuxt-08]: Routing-Middlewares

In diesem Beispiel führen wir das Konzept der Routing-Middlewares ein, also Skripte, die bei jedem Routenwechsel ausgeführt werden.

Das Beispiel [nuxt-08] wird zunächst durch Kopieren des Projekts [nuxt-01] erstellt:

Image

Die Routing-Middlewares müssen sich in einem Ordner namens [middleware] [2] befinden. Es kann ein zweistufiges Routing geben:

  • eine Routing-Regel, die bei jedem Navigationsschritt angewendet wird. Diese wird dann in der Datei „[nuxt.config.js]“ deklariert;
  • eine Weiterleitung, die auf eine bestimmte Seite angewendet wird, wenn diese das Ziel der Weiterleitung ist. Diese Weiterleitung wird dann in dieser Zielseite deklariert;

11.1. Allgemeine Weiterleitung

Die Datei [middleware / routing.js] sorgt für die allgemeine Weiterleitung. Sie wird in der Datei [nuxt.config.js] wie folgt deklariert:


  router: {
    base: '/nuxt-08/',
    middleware: ['routing']
},

Die Middlewares für das allgemeine Routing sind eine Eigenschaft des Routers (Zeile 1). Es kann mehrere Routing-Middlewares geben. Deshalb ist in Zeile 3 der Wert der Eigenschaft [middleware] ein Array. Man sieht, dass kein Pfad zur Angabe der Middleware verwendet wird. Diese wird automatisch im Ordner „[middleware]“ des Projekts gesucht;

Die Middleware [routing] erstellt hier lediglich Protokolle:


/* eslint-disable no-undef */
/* eslint-disable no-console */
export default function(...args) {
  // Wer führt diesen Code aus?
  console.log('[routing], process.server=', process.server, 'process.client=', process.client)
  const who = process.server ? 'server' : 'client'
  const routing = '[routing ' + who + ']'
  // Anzahl der Argumente
  console.log(routing + ', il y a', args.length, 'argument(s)')

  // 1. Argument
  const context = args[0]
  // Kontextschlüssel
  dumpkeys(routing + ', context', context)
  // die Anwendung
  dumpkeys(routing + ', context.app', context.app)
  // die Route
  dumpkeys(routing + ', context.route', context.route)
  console.log(routing + ', context.route=', context.route)
  // der Router
  dumpkeys(routing + ', context.app.router', context.app.router)
  // der 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) {
  // Liste der Schlüssel von [object]
  const ligne = 'Liste des clés [' + message + ']'
  console.log(ligne)
  // Liste der Schlüssel
  if (object) {
    console.log(Object.keys(object))
  }
}
  • Zeile 3: Wir werden feststellen, dass die Middleware ein Argument erhält: den Kontext des Ausführenden (Server oder Client);
  • Zeilen 4–25: Wir zeigen die Eigenschaften verschiedener Objekte an, um herauszufinden, was verwendbar ist. Wir werden feststellen, dass der Kontext der Middleware nahezu identisch mit dem Kontext des Plugins ist;

11.2. Weiterleitung zu einer bestimmten Seite

Wir möchten steuern, wie man zur Seite [index] gelangt. Dazu müssen wir die Eigenschaft [middleware] in diese Seite [index] einfügen:


<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',
  // verwendete Komponenten
  components: {
    Layout,
    Navigation
  },
  // Lebenszyklus
  beforeCreate() {
    // Client und Server
    console.log('[home beforeCreate]')
  },
  created() {
    // Client und Server
    console.log('[home created]')
  },
  beforeMount() {
    // nur Client
    console.log('[home beforeMount]')
  },
  mounted() {
    // nur Client
    console.log('[home mounted]')
  },
  // Routing
  middleware: ['index-routing']
}
</script>
  • Zeile 34: Die Eigenschaft [middleware] listet die Skripte auf, die jedes Mal ausgeführt werden sollen, wenn die nächste angezeigte Seite die Seite [index] ist. Auch hier werden diese Skripte im Ordner [middleware] des Projekts gesucht;

Die Middleware [index-routing] lautet wie folgt:


/* eslint-disable no-undef */
/* eslint-disable no-console */
export default function(...args) {
  // Wer führt diesen Code aus?
  console.log('[index-routing], process.server=', process.server, 'process.client=', process.client)
  const who = process.server ? 'server' : 'client'
  const indexRouting = '[index-routing ' + who + ']'
  // Anzahl der Argumente
  console.log(indexRouting + ', il y a', args.length, 'argument(s)')

  // 1. Argument
  const context = args[0]
  // Kontextschlüssel
  dumpkeys(indexRouting + ', context', context)
  // die Anwendung
  dumpkeys(indexRouting + ', context.app', context.app)
  // die Route
  dumpkeys(indexRouting + ', context.route', context.route)
  console.log(indexRouting + ', context.route=', context.route)
  // der Router
  dumpkeys(indexRouting + ', context.app.router', context.app.router)
  // der 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)
  // Woher kommen wir?
  if (context.from) {
    console.log('from=', context.from)
  }
}

function dumpkeys(message, object) {
  // Liste der Schlüssel von [object]
  const ligne = 'Liste des clés [' + message + ']'
  console.log(ligne)
  // Liste der Schlüssel
  if (object) {
    console.log(Object.keys(object))
  }
}

Der Code von [index-routing] ist identisch mit dem von [routing] und liefert dieselben Ergebnisse. Uns interessiert vor allem, wann diese beiden Middlewares ausgeführt werden.

11.3. Ausführung des Projekts

Wir führen das Projekt aus. Die Protokolle sehen dann wie folgt aus:

Das Skript [routing] wird vom Server als Erstes ausgeführt:

[routing], process.server= true process.client= false
[routing server], il y a 1 argument(s)
Liste des clés [[routing server], context]
[ 'isStatic',
  'isDev',
  'isHMR',
  'app',
  'payload',
  'error',
  'base',
  'env',
  'req',
  'res',
  'ssrContext',
  'redirect',
  'beforeNuxtRender',
  'route',
  'next',
  '_redirected',
  '_errored',
  'params',
  'query',
   '$axios' ]
Liste des clés [[routing server], context.app]
[ 'router',
  'nuxt',
  'head',
  'render',
  'data',
  'beforeCreate',
  'created',
  'mounted',
  'watch',
  'computed',
  'methods',
  'components',
  'context',
   '$axios' ]
Liste des clés [[routing server], context.route]
[ 'name',
  'meta',
  'path',
  'hash',
  'query',
  'params',
  'fullPath',
  'matched' ]
[routing server], context.route= { name: 'index',
  meta: [ {} ],
  path: '/',
  hash: '',
  query: {},
  params: {},
  fullPath: '/',
  matched:
   [ { path: '',
       regex: /^(?:\/(?=$))?$/i,
       components: [Object],
       instances: {},
       name: 'index',
       parent: undefined,
       matchAs: undefined,
       redirect: undefined,
       beforeEnter: undefined,
       meta: {},
       props: {} } ] }
Liste des clés [[routing server], context.app.router]
[ 'app',
  'apps',
  'options',
  'beforeHooks',
  'resolveHooks',
  'afterHooks',
  'matcher',
  'fallback',
  'mode',
  'history' ]
Liste des clés [[routing server], context.app.router.options.routes]
[ '0', '1', '2' ]
[routing server], context.app.router.options.routes= [ { path: '/page1',
    component: [Function: _61cefe10],
    name: 'page1' },
  { path: '/page2',
    component: [Function: _61dd1591],
    name: 'page2' },
  { path: '/', component: [Function: _00d5e140], name: 'index' } ]

Hier sehen wir das gleiche Ergebnis wie bei den Plugins.

  • Zeile 15: Die Eigenschaft [redirect] wird häufig in Middlewares verwendet: Sie ermöglicht es, das Ziel des laufenden Routings zu ändern;

Da nun die Seite [index] angezeigt werden soll, führt der Server das Skript [index-routing] aus und gibt die folgenden Protokolleinträge aus:

[index-routing], process.server= true process.client= false
[index-routing server], il y a 1 argument(s)
Liste des clés [[index-routing server], context]
[ 'isStatic',
  'isDev',
  'isHMR',
  'app',
  'payload',
  'error',
  'base',
  'env',
  'req',
  'res',
  'ssrContext',
  'redirect',
  'beforeNuxtRender',
  'route',
  'next',
  '_redirected',
  '_errored',
  'params',
  'query',
   '$axios' ]
Liste des clés [[index-routing server], context.app]
[ 'router',
  'nuxt',
  'head',
  'render',
  'data',
  'beforeCreate',
  'created',
  'mounted',
  'watch',
  'computed',
  'methods',
  'components',
  'context',
   '$axios' ]
Liste des clés [[index-routing server], context.route]
[ 'name',
  'meta',
  'path',
  'hash',
  'query',
  'params',
  'fullPath',
  'matched' ]
[index-routing server], context.route= { name: 'index',
  meta: [ {} ],
  path: '/',
  hash: '',
  query: {},
  params: {},
  fullPath: '/',
  matched:
   [ { path: '',
       regex: /^(?:\/(?=$))?$/i,
       components: [Object],
       instances: {},
       name: 'index',
       parent: undefined,
       matchAs: undefined,
       redirect: undefined,
       beforeEnter: undefined,
       meta: {},
       props: {} } ] }
Liste des clés [[index-routing server], context.app.router]
[ 'app',
  'apps',
  'options',
  'beforeHooks',
  'resolveHooks',
  'afterHooks',
  'matcher',
  'fallback',
  'mode',
  'history' ]
Liste des clés [[index-routing server], context.app.router.options.routes]
[ '0', '1', '2' ]
[index-routing server], context.app.router.options.routes= [ { path: '/page1',
    component: [Function: _61cefe10],
    name: 'page1' },
  { path: '/page2',
    component: [Function: _61dd1591],
    name: 'page2' },
  { path: '/', component: [Function: _00d5e140], name: 'index' } ]

Die mit dem Skript [index-routing] erzielten Ergebnisse entsprechen denen des Skripts [routing].

Sobald die Seite [index] vom Client-Browser empfangen wurde, übernehmen die Client-Skripte die Kontrolle. Die Protokolle lauten nun wie folgt:

1
2
3
4
[home beforeCreate]
[home created]
[home beforeMount]
[home mounted]

Man sieht also, dass der Client beim Start der Anwendung keine Middleware ausführt. Das bedeutet, dass dies jedes Mal geschieht, wenn der Benutzer einen Aufruf an den Server auslöst. Die Middleware wird vom Client nur bei der Navigation innerhalb der Anwendung ausgeführt. Navigieren wir beispielsweise über den Link [Page 1] zur Seite [page1] (wir befinden uns derzeit auf der Seite [index]). Die Logs sehen dann wie folgt aus:

[routing], process.server= false process.client= true
[routing client], il y a 1 argument(s)
Liste des clés [[routing client], context]
(18) ["isStatic", "isDev", "isHMR", "app", "payload", "error", "base", "env", "redirect", "nuxtState", "route", "next", "_redirected", "_errored", "params", "query", "$axios", "from"]
Liste des clés [[routing client], context.app]
(14) ["router", "nuxt", "head", "render", "data", "beforeCreate", "created", "mounted", "watch", "computed", "methods", "components", "context", "$axios"]
Liste des clés [[routing client], context.route]
(8) ["name", "meta", "path", "hash", "query", "params", "fullPath", "matched"]
[routing client], context.route= {name: "page1", meta: Array(1), path: "/page1", hash: "", query: {}, }
Liste des clés [[routing client], context.app.router]
(10) ["app", "apps", "options", "beforeHooks", "resolveHooks", "afterHooks", "matcher", "fallback", "mode", "history"]
Liste des clés [[routing client], context.app.router.options.routes]
(3) ["0", "1", "2"]
[routing client], context.app.router.options.routes= (3) [{}, {}, {}]0: {path: "/page1", name: "page1", component: ƒ}1: {path: "/page2", name: "page2", component: ƒ}2: {path: "/", name: "index", component: ƒ}length: 3__proto__: Array(0)
[page1 beforeCreate]
[page1 created]
[page1 beforeMount]
[page1 mounted]
  • Zeile 2: Die Middleware [routing] wird vom Client ausgeführt;
  • Zeile 4: Beachten Sie die Eigenschaft [from]: Dies ist die Route, von der wir kommen;
  • Zeile 9: [context.route] ist die Route, zu der man wechselt;
  • Zeilen 15–18: Anzeige der Seite [page1];

Kehren wir nun über den Link [Home] zur Seite [index] zurück. Die Protokolleinträge lauten dann wie folgt:

[routing], process.server= false process.client= true
[routing client], il y a 1 argument(s)
Liste des clés [[routing client], context]
(18) ["isStatic", "isDev", "isHMR", "app", "payload", "error", "base", "env", "redirect", "nuxtState", "route", "next", "_redirected", "_errored", "params", "query", "$axios", "from"]
Liste des clés [[routing client], context.app]
(14) ["router", "nuxt", "head", "render", "data", "beforeCreate", "created", "mounted", "watch", "computed", "methods", "components", "context", "$axios"]
Liste des clés [[routing client], context.route]
(8) ["name", "meta", "path", "hash", "query", "params", "fullPath", "matched"]
[routing client], context.route= {name: "index", meta: Array(1), path: "/", hash: "", query: {}, }
Liste des clés [[routing client], context.app.router]
(10) ["app", "apps", "options", "beforeHooks", "resolveHooks", "afterHooks", "matcher", "fallback", "mode", "history"]
Liste des clés [[routing client], context.app.router.options.routes]
(3) ["0", "1", "2"]
[routing client], context.app.router.options.routes= (3) [{}, {}, {}]0: {path: "/page1", name: "page1", component: ƒ}1: {path: "/page2", name: "page2", component: ƒ}2: {path: "/", name: "index", component: ƒ}length: 3__proto__: Array(0)
[index-routing], process.server= false process.client= true
[index-routing client], il y a 1 argument(s)
Liste des clés [[index-routing client], context]
(18) ["isStatic", "isDev", "isHMR", "app", "payload", "error", "base", "env", "redirect", "nuxtState", "route", "next", "_redirected", "_errored", "params", "query", "$axios", "from"]
Liste des clés [[index-routing client], context.app]
(14) ["router", "nuxt", "head", "render", "data", "beforeCreate", "created", "mounted", "watch", "computed", "methods", "components", "context", "$axios"]
Liste des clés [[index-routing client], context.route]
(8) ["name", "meta", "path", "hash", "query", "params", "fullPath", "matched"]
[index-routing client], context.route= {name: "index", meta: Array(1), path: "/", hash: "", query: {}, }
Liste des clés [[index-routing client], context.app.router]
(10) ["app", "apps", "options", "beforeHooks", "resolveHooks", "afterHooks", "matcher", "fallback", "mode", "history"]
Liste des clés [[index-routing client], context.app.router.options.routes]
(3) ["0", "1", "2"]
[index-routing client], context.app.router.options.routes= (3) [{}, {}, {}]0: {path: "/page1", name: "page1", component: ƒ}1: {path: "/page2", name: "page2", component: ƒ}2: {path: "/", name: "index", component: ƒ}length: 3__proto__: Array(0)
from= {name: "page1", meta: Array(1), path: "/page1", hash: "", query: {}, }
[home beforeCreate]
[home created]
[home beforeMount]
[home mounted]
  • Zeilen 1–15: Der Client führt die Middleware [routing] aus. Das ist normal. Sie wird bei jedem Routenwechsel ausgeführt;
  • Zeilen 16–29: Der Client führt die Middleware [index-routing] aus, und zwar aus folgendem Grund:
    • [index] das Ziel der aktuellen Route ist (siehe Zeile 23);
    • die Seite [index] hat eine Middleware definiert, nämlich [index-routing];

Man sieht also, dass die allgemeinen Routing-Middlewares vom Client vor den an die Seiten angehängten Middlewares ausgeführt werden.