16. Beispiel [nuxt-13]: Überprüfung der Navigation von [nuxt-12]
In diesem Beispiel konzentrieren wir uns auf die Navigation von [nuxt-12]. Wir haben dies in [nuxt-12] nicht getan, da die Steuerung der Navigation ein ohnehin schon komplexes Beispiel noch weiter verkompliziert hätte.
Ziel: Wir möchten, dass der Benutzer nur autorisierte Aktionen ausführen kann:
- Wenn die JSON-Sitzung noch nicht gestartet wurde, ist nur die URL [/] zulässig;
- Wenn die JSON-Sitzung gestartet wurde, der Benutzer aber nicht authentifiziert ist, ist nur die URL [/authentication] zulässig;
- Wenn die JSON-Sitzung gestartet wurde und der Benutzer authentifiziert ist, sind nur die URLs [/get-admindata, /end-session] zulässig;
- wenn das aktuelle Routing-Ziel nicht autorisiert ist, erfolgt eine Weiterleitung zu einer autorisierten URL;
Das Beispiel [nuxt-13] wird zunächst durch Kopieren des Beispiels [nuxt-12] erstellt:

Die Änderungen werden im Routing-Ordner [middleware] vorgenommen.
16.1. Routing für die [nuxt]-Anwendung
Das Routing der Anwendung wird in der Datei [nuxt.config] wie folgt konfiguriert:
// router
router: {
// application URL root
base: '/nuxt-13/',
// routing middleware
middleware: ['routing']
},
- Zeile 6: Das Routing der Anwendung wird durch die Datei [middleware/routing] gesteuert;
Die [middleware/routing]-Datei sieht wie folgt aus:
/* eslint-disable no-console */
// on importe les middleware du serveur et du client
import serverRouting from './server/routing'
import clientRouting from './client/routing'
export default function(context) {
// qui exécute ce code ?
console.log('[middleware], process.server', process.server, ', process.client=', process.client)
if (process.server) {
// routage serveur
serverRouting(context)
} else {
// routage client
clientRouting(context)
}
}
- Zeilen 10–16: Das Routing für Client und Server [nuxt] wird unterschiedlich gehandhabt. Dies ist ein wesentlicher Unterschied zwischen beiden;
- Zeile 4: Das Server-Routing wird durch das Skript [middleware/server/routing] implementiert;
- Zeile 5: Das Client-Routing wird durch das Skript [middleware/client/routing] implementiert;
16.2. [nuxt] Client-Routing
Das clientseitige Routing [nuxt] bleibt unverändert gegenüber [nuxt-12]:
/* eslint-disable no-console */
export default function(context) {
// who executes this code?
console.log('[middleware client], process.server', process.server, ', process.client=', process.client)
// management of the PHP session cookie in the browser
// the browser's PHP session cookie must be identical to the one found in the nuxt session
// acion [fin-session] receives a new cookie PHP (server as nuxt client)
// if the server receives it, the client must pass it on to the browser
// for its own exchanges with the PHP server
// this is customer routing
// retrieve the session cookie PHP
const phpSessionCookie = context.store.state.phpSessionCookie
if (phpSessionCookie) {
// if it exists, we assign the PHP session cookie to the browser
document.cookie = phpSessionCookie
}
...
}
Um zu verhindern, dass der Client auf nicht autorisierte Routen zugreift, bieten wir im Navigationsmenü des Clients einfach nur die autorisierten Routen an. Die Komponente [components/navigation] sieht dann wie folgt aus:
<template>
<!-- bootstrap menu with three options -->
<b-nav vertical>
<b-nav-item v-if="$store.state.jsonSessionStarted && !$store.state.userAuthenticated" to="/authentification" exact exact-active-class="active">
Authentification
</b-nav-item>
<b-nav-item
v-if="$store.state.jsonSessionStarted && $store.state.userAuthenticated && !$store.state.adminData"
to="/get-admindata"
exact
exact-active-class="active"
>
Requête AdminData
</b-nav-item>
<b-nav-item v-if="$store.state.jsonSessionStarted && $store.state.userAuthenticated" to="/fin-session" exact exact-active-class="active">
Fin session impôt
</b-nav-item>
</b-nav>
</template>
- Zeile 4: Die Option [Authentication] ist nur verfügbar, wenn die JSON-Sitzung gestartet wurde, der Benutzer jedoch noch nicht authentifiziert ist. Wenn die JSON-Sitzung noch nicht gestartet wurde oder der Benutzer bereits authentifiziert ist, ist die Option nicht verfügbar;
- Zeilen 7–11: Die Option [AdminData Request] ist nur verfügbar, wenn die JSON-Sitzung gestartet wurde, der Benutzer authentifiziert ist und die [AdminData] noch nicht abgerufen wurden. Wenn eine dieser drei Bedingungen nicht erfüllt ist (JSON-Sitzung nicht gestartet, Benutzer nicht authentifiziert oder [AdminData] bereits abgerufen), wird die Option nicht angeboten;
- Zeile 15: Die Option [End Tax Session] ist verfügbar, sobald die JSON-Sitzung gestartet wurde und der Benutzer authentifiziert ist; andernfalls ist sie nicht verfügbar;
16.3. Server-Routing [Nuxt]
Server-Routing ist im Allgemeinen komplexer als clientseitiges Routing, da der Benutzer eine beliebige URL in die Adressleiste seines Browsers eingeben kann. Wir können dies zulassen (schließlich soll der Benutzer das eigentlich nicht tun) oder versuchen, es zu kontrollieren. Genau das werden wir hier im Rahmen dieses Beispiels tun, denn im Fall der [nuxt-12]-Anwendung können wir leicht darauf verzichten, da der Steuerberechnungsserver gut gegen diese manuell eingegebenen URLs geschützt ist und weiß, wie er die entsprechenden Fehlermeldungen senden muss. Das haben wir in [next-12] gesehen, wo es keine Routing-Kontrolle gab.
Das Routing auf einem [nuxt]-Server unterscheidet sich in Bezug auf die Weiterleitung stark von dem auf einem [nuxt]-Client:
- Wenn ein [nuxt]-Server umgeleitet wird, sendet er eine Umleitungsanfrage mit dem Umleitungsziel an den Client-Browser. Der Browser stellt daraufhin eine neue Anfrage an den [nuxt]-Server und fragt nach dem Ziel, das ihm gesendet wurde. Es ist, als hätte der Benutzer die URL des Umleitungsziels manuell eingegeben: Die gesamte [nuxt]-Anwendung wird neu gestartet, und mit ihr ihr gesamter Lebenszyklus (Server-Plugins, Store, Server-Routing, Seiten);
- Wenn ein [nuxt]-Client umgeleitet wird, geschieht nichts davon. Es findet lediglich ein Seitenwechsel statt, genau wie es der Fall wäre, wenn der Benutzer auf einen Link geklickt hätte, der zum Umleitungsziel führt. Der Lebenszyklus verläuft dann anders (clientseitiges Routing, Rendern des Routenziels);
Aus diesem Grund ist es vorzuziehen, das clientseitige Routing vom serverseitigen Routing zu trennen, auch wenn die beiden Codebasen ähnlich erscheinen mögen.
Das Server-Routing-Skript [middleware/server/routing] sieht wie folgt aus:
/* eslint-disable no-console */
export default function(context) {
// qui exécute ce code ?
console.log('[middleware server], process.server', process.server, ', process.client=', process.client)
// on récupère quelques informations dans le store [nuxt]
const store = context.store
// d'où vient-on ?
const from = store.state.from || 'nowhere'
...
}
- Beim clientseitigen Routing erhält die Routing-Funktion den Kontext [context] mit der Eigenschaft [context.from], die die Route der Seite angibt, von der wir gekommen sind. Die Route, zu der wir gehen, wird über [context.route] abgerufen;
- Beim serverseitigen Routing erhält die Routing-Funktion den Kontext [context] ohne die Eigenschaft [context.from]. Serverseitiges Routing findet nur statt, wenn eine URL manuell vom [nuxt]-Server angefordert wird. Wir wissen, dass die gesamte [nuxt]-Anwendung dann zurückgesetzt wird. Es ist, als würden wir von vorne beginnen, daher gibt es kein Konzept einer „vorherigen Seite“;
- Dank der [nuxt]-Sitzung wissen wir, dass der Server diese Sitzung abrufen und somit vermeiden kann, bei Null anzufangen. Daher speichern wir in dieser [nuxt]-Sitzung, genauer gesagt im Store der Sitzung, den Namen der letzten Seite, die vom Client-Browser angezeigt wurde, bevor eine URL vom [nuxt]-Server angefordert wurde;
- Zeilen 7–9: Wir rufen den Namen der letzten Seite ab, die vom Client-Browser angezeigt wurde. Beim Start der Anwendung ist diese Information [from] im Store nicht vorhanden. Wir weisen der Variablen [from] dann den Namen [nowhere] zu;
Damit der [nuxt]-Server den Namen der zuletzt vom Client-Browser angezeigten Seite aus dem Store abrufen kann, muss der [nuxt]-Client diese Information ebenfalls in den Store schreiben. Das [nuxt]-Client-Routing-Skript wird daher wie folgt vervollständigt:
/* eslint-disable no-console */
export default function(context) {
// qui exécute ce code ?
console.log('[middleware client], process.server', process.server, ', process.client=', process.client)
// gestion du cookie de la session PHP dans le navigateur
// le cookie de la session PHP du navigateur doit être identique à celui trouvé en session nuxt
// l'acion [fin-session] reçoit un nouveau cookie PHP (serveur comme client nuxt)
// si c'est le serveur qui le reçoit, le client doit le transmettre au navigateur
// pour ses propres échanges avec le serveur PHP
// on est ici dans un routing client
// on récupère le cookie de la session PHP
const phpSessionCookie = context.store.state.phpSessionCookie
if (phpSessionCookie) {
// s'il existe, on affecte le cookie de session PHP au navigateur
document.cookie = phpSessionCookie
}
// on met dans la session le nom de la page où on va - pas de redirection serveur
context.store.commit('replace', { serverRedirection: false, from: context.route.name })
// on sauvegarde le store dans la session [nuxt]
const session = context.app.$session()
session.value.store = context.store.state
session.save(context)
}
- Die Zeilen 19–24 werden hinzugefügt;
- Zeile 20: Wir speichern den Namen der Seite [context.route.name], die im Store angezeigt wird, der dann beim nächsten Routing-Schritt als die Seite dient, von der wir gekommen sind. Außerdem werden wir sehen, dass das Routing des [nuxt]-Servers wissen muss, ob das aktuelle Routing auf einer vorherigen Umleitung durch den [nuxt]-Server beruht. Hier ist das nicht der Fall, daher setzen wir die Eigenschaft [serverRedirection] auf [false];
- Zeilen 22–24: Der Status des Stores wird in die [nuxt]-Session geschrieben (Zeile 23), anschließend wird die [nuxt]-Session in einem Cookie gespeichert (Zeile 24), das wiederum im Browser des [nuxt]-Clients gespeichert wird;
Kehren wir zum Routing-Skript des [nuxt]-Servers zurück:
/* eslint-disable no-console */
export default function(context) {
// qui exécute ce code ?
console.log('[middleware server], process.server', process.server, ', process.client=', process.client)
// on récupère quelques informations dans le store [nuxt]
const store = context.store
// d'où vient-on ?
const from = store.state.from || 'nowhere'
// où va-t-on ?
const to = context.route.name
// éventuelle redirection
let redirection = ''
// gestion du routage terminé
let done = false
// est-on déjà dans une redirection du serveur [nuxt]?
if (store.state.serverRedirection) {
// rien à faire
done = true
}
// est-ce un rechargement de page ?
if (to === from) {
// rien à faire
done = true
}
// contrôle de la navigation du serveur [nuxt]
// on s'inspire de la navigation client dans le composant [navigation]
// cas où la session PHP n'a pas démarré
if (!done && !store.state.jsonSessionStarted && to !== 'index') {
// redirection
redirection = 'index'
// travail terminé
done = true
}
// cas où l'utilisateur n'est pas authentifié
if (!done && store.state.jsonSessionStarted && !store.state.userAuthenticated && to !== 'authentification') {
// redirection
redirection = from
// travail terminé
done = true
}
// cas où l'utilisateur a été authentifié
if (!done && store.state.jsonSessionStarted && store.state.userAuthenticated && to !== 'get-admindata' && to !== 'fin-session') {
// on reste sur la même page
redirection = from
// travail terminé
done = true
}
// cas où [adminData] a été obtenu
if (!done && store.state.jsonSessionStarted && store.state.userAuthenticated && store.state.adminData && to !== 'fin-session') {
// on reste sur la même page
redirection = from
// travail terminé
done = true
}
// on a fait tous les contrôles ---------------------
// redirection ?
if (redirection) {
// on note la redirection dans le store
store.commit('replace', { serverRedirection: true })
} else {
// pas de redirection
store.commit('replace', { serverRedirection: false, from: to })
}
// on sauvegarde le store dans la session [nuxt]
const session = context.app.$session()
session.value.store = store.state
session.save(context)
// on fait l'éventuelle redirection
if (redirection) {
context.redirect({ name: redirection })
}
}
- Zeilen 6–9: Abrufen des Werts von [from] aus dem [nuxt]-Server-Store;
- Zeile 11: Wir notieren das Ziel der aktuellen Route;
- Zeile 13: Das Routing kann zu einer Weiterleitung des Client-Browsers führen. [redirection] ist das Ziel dieser Weiterleitung;
- Zeile 15: [done] auf [true] gesetzt zeigt an, dass das Routing abgeschlossen ist;
- Zeilen 17–21: Zunächst prüfen wir, ob das aktuelle Routing aus einer an den Client-Browser gesendeten Umleitungsanforderung resultiert. Diese Information ist in der Eigenschaft [serverRedirection] des Speichers abgelegt. Ist diese Eigenschaft wahr, hat der [nuxt]-Server während der vorherigen Anfrage an den [nuxt]-Server eine Umleitung an den Client-Browser gesendet. In diesem Fall ist kein Routing erforderlich. Während der vorherigen Anfrage hat der [nuxt]-Server-Router entschieden, dass der Client-Browser umgeleitet werden soll. Diese Entscheidung muss nicht durch ein neues Routing überschrieben werden;
- Zeilen 23–27: Wir prüfen, ob das aktuelle Routing ein Seitenneuladen ist. Wenn ja, lassen wir es fortfahren;
- Ab Zeile 29 setzen wir die Regeln fort, die in der [navigation]-Komponente des [nuxt]-Clients angewendet werden (siehe vorheriger Absatz);
- Zeilen 32–38: Wir behandeln den Fall, in dem die JSON-Sitzung noch nicht gestartet wurde und das Routing-Ziel nicht die [index]-Seite ist. In diesem Fall leiten wir den Client-Browser auf die [index]-Seite um;
- Zeilen 40–46: Wir behandeln den Fall, in dem die JSON-Sitzung gestartet wurde, der Benutzer nicht authentifiziert ist und das aktuelle Routing-Ziel nicht die [authentication]-Seite ist. In diesem Fall lehnen wir das Routing ab und bleiben dort, wo wir waren;
- Zeilen 48–54: Behandelt den Fall, in dem die JSON-Sitzung gestartet wurde, der Benutzer authentifiziert ist und das aktuelle Routing-Ziel weder die [get-admindata]-Seite noch die [end-session]-Seite ist, die dann die einzigen möglichen Ziele sind. In diesem Fall wird das angeforderte Routing abgelehnt, und wir kehren an die vorherige Stelle zurück;
- Zeilen 56–62: Wir behandeln den Fall, in dem [adminData] abgerufen wurde. In diesem Fall gibt es nur ein mögliches Routing-Ziel: die Seite [fin-session]. Wenn dies nicht die angeforderte Seite war, lehnen wir das Routing ab und kehren an die vorherige Stelle zurück;
- Zeilen 64–72: Wenn eine Weiterleitung stattgefunden hat, speichern wir dies im [nuxt]-Server-Store: [serverRedirection: true]. Beachten Sie, dass wir der [from]-Eigenschaft des Speichers keinen Wert zuweisen. Der Grund dafür ist, dass eine Weiterleitung vom Client-Browser erfolgt, und wir haben gesehen, dass in diesem Fall kein Routing stattfand (Zeilen 17–20) und die [from]-Eigenschaft des Speichers nicht verwendet wird;
- Zeilen 66–69: Wenn keine Weiterleitung stattfindet, wird dies ebenfalls im [nuxt]-Server-Store vermerkt: [serverRedirection: false]. Zusätzlich wird das aktuelle Routing die [to]-Seite anzeigen, die für die nächste Anfrage (Client oder [nuxt]-Server) zur vorherigen Seite wird. Deshalb schreiben wir [from: to];
- Zeilen 73–76: Wir speichern den Store in der [nuxt]-Session, die wiederum in einem Cookie gespeichert wird;
- Zeilen 77–80: Wenn [redirection] nicht leer ist, weisen wir den Browser an, eine Weiterleitung durchzuführen. Andernfalls (hier nicht dargestellt) wird der Lebenszyklus des [nuxt]-Servers fortgesetzt: Die [to]-Seite wird vom [nuxt]-Server verarbeitet und zusammen mit dem [nuxt]-Session-Cookie an den Browser des [nuxt]-Clients gesendet;
Das hier für den [nuxt]-Server gewählte Routing ist willkürlich. Wir hätten auch ein anderes wählen oder, wie erwähnt, gar kein Routing verwenden können. Das oben gewählte hat den Vorteil, dass die Anwendung unabhängig von der vom Benutzer angeforderten URL stets in einem stabilen Zustand bleibt.
Wir können dies leicht verbessern, wenn die Seite, die letztendlich geladen wird, die ursprüngliche Seite ist. Es gibt zwei Fälle:
- Der Benutzer hat einen Seitenneuladung ausgelöst (to===from);
- es gibt Weiterleitungen zur ursprünglichen Seite (redirection===from);
In beiden Fällen wird die ursprüngliche Seite erneut ausgeführt, einschließlich ihres asynchronen Aufrufs an den Steuerberechnungsserver. Nehmen wir ein Beispiel: Wenn der Benutzer nach der Authentifizierung die Seite neu lädt (F5). In diesem Fall haben wir im obigen Routing: [to]=[from]=[authentication]. Es gibt keine Weiterleitung. Die Seite [to=authentication] wird vom [nuxt]-Server ausgeführt. Wenn wir nichts unternehmen, wird die Funktion [asyncData] erneut ausgeführt. Dies ist unnötig, da die Authentifizierung bereits durchgeführt wurde.
Wir können dies verbessern, indem wir die Seite [authentication] leicht modifizieren:
// asynchronous data
async asyncData(context) {
// log
console.log('[authentification asyncData started]')
// don't do things twice if the page has already been requested
if (process.server && context.store.state.userAuthenticated) {
console.log('[authentification asyncData canceled]')
return { result: '[succès]' }
}
// customer [nuxt]
if (process.client) {
// start waiting
context.app.$eventBus().$emit('loading', true)
// no error
context.app.$eventBus().$emit('errorLoading', false)
}
try {
// authenticate to the server
...
- Zeilen 6–9: Wenn die Seite vom [nuxt]-Server bereitgestellt wird und wir im Store feststellen, dass die Authentifizierung bereits erfolgt ist, geben wir das gewünschte Ergebnis direkt zurück (Zeile 8);
Wir verfahren bei allen Seiten genauso:
Seite [index]:
// asynchronous data
async asyncData(context) {
// log
console.log('[index asyncData started]')
// don't do things twice if the page has already been requested
if (process.server && context.store.state.jsonSessionStarted) {
console.log('[index asyncData canceled]')
return { result: '[succès]' }
}
try {
...
Seite [get-admindata]
// asynchronous data
async asyncData(context) {
// log
console.log('[get-admindata asyncData started]')
// don't do things twice if the page has already been requested
if (process.server && context.store.state.adminData) {
console.log('[get-admindata asyncData canceled]')
return { result: context.store.state.adminData }
}
// customer
if (process.client) {
// start waiting
context.app.$eventBus().$emit('loading', true)
// no error
context.app.$eventBus().$emit('errorLoading', false)
}
try {
...
Seite [Sitzung beenden]
// asynchronous data
async asyncData(context) {
// log
console.log('[fin-session asyncData started]')
// don't do things twice if the page has already been requested
if (process.server && context.store.state.jsonSessionStarted && !context.store.state.userAuthenticated) {
console.log('[fin-session asyncData canceled]')
return { result: "[succès]. La session jSON reste initialisée mais vous n'êtes plus authentifié(e)." }
}
// customer case [nuxt]
if (process.client) {
// start waiting
context.app.$eventBus().$emit('loading', true)
// no error
context.app.$eventBus().$emit('errorLoading', false)
}
try {
16.4. Ausführung
Um dieses Beispiel auszuführen, stellen Sie sicher, dass Sie vor der Ausführung das [nuxt]-Sitzungscookie und das PHP-Cookie aus dem Browser löschen, in dem der [nuxt]-Client läuft, um mit einer sauberen Basis zu beginnen. Nachfolgend finden Sie ein Beispiel für den Chrome-Browser:

16.5. Fazit
Das Routing auf dem [nuxt]-Server ist komplex, da Sie jede URL vorhersehen müssen, die der Benutzer manuell eingeben könnte. Dies ist ein Lehrbuchbeispiel. Eine [nuxt]-Anwendung ist nicht für eine solche Verwendung vorgesehen. Sobald die [index]-Seite vom Router des [nuxt]-Servers bereitgestellt wurde, könnten nachfolgende Anfragen an den Server auf eine Fehlerseite umgeleitet werden.
Im konkreten Fall unseres [nuxt-13]-Beispiels war das [nuxt]-Server-Routing unnötig. Das Standardverhalten (im Wesentlichen kein Routing) im [nuxt-12]-Beispiel funktionierte einwandfrei.