16. Voorbeeld [nuxt-13]: controle van de navigatie van [nuxt-12]
In dit voorbeeld richten we ons op de navigatie van [nuxt-12]. We hebben dit niet gedaan in [nuxt-12], omdat het controleren van de navigatie een toch al complex voorbeeld nog ingewikkelder zou hebben gemaakt.
Doel: we willen dat de gebruiker alleen toegestane acties kan uitvoeren:
- als de sessie jSON niet is gestart, dan is alleen de sessie URL [/] toegestaan;
- als de sessie jSON is gestart maar de gebruiker niet is geauthenticeerd, dan zijn alleen de sessies URL en [/authentification] toegestaan;
- als de sessie jSON is gestart en de gebruiker is geauthenticeerd, dan zijn alleen de sessies URL en [/get-admindata, /fin-session] toegestaan;
- wanneer het huidige routeringsdoel niet is toegestaan, wordt er omgeleid naar een toegestane URL;
Het voorbeeld [nuxt-13] wordt in eerste instantie verkregen door het voorbeeld [nuxt-12] te kopiëren:

De wijzigingen zullen plaatsvinden in de routeringsmap van [middleware].
16.1. Routering van de applicatie [nuxt]
De routing van de applicatie is als volgt geconfigureerd in het bestand [nuxt.config]:
// router
router: {
// hoofdmap van de applicatie URL
base: '/nuxt-13/',
// routeringsmiddleware
middleware: ['routing']
},
- regel 6: de applicatieroutering wordt geregeld door het bestand [middleware/routing];
Het bestand [middleware/routing] ziet er als volgt uit:
/* eslint-disable no-console */
// we importeren de server- en client-middleware
import serverRouting from './server/routing'
import clientRouting from './client/routing'
export default function(context) {
// Wie voert deze code uit?
console.log('[middleware], process.server', process.server, ', process.client=', process.client)
if (process.server) {
// serverroutering
serverRouting(context)
} else {
// clientroutering
clientRouting(context)
}
}
- regels 10-16: de routering van de client en de server [nuxt] wordt verschillend behandeld. Dit is een punt waarop ze sterk van elkaar verschillen;
- regel 4: de serverrouting wordt geïmplementeerd door het script [middleware/server/routing];
- regel 5: de client-routing wordt geïmplementeerd door het script [middleware/client/routing];
16.2. Clientroutering [nuxt]
De client-routing [nuxt] blijft hetzelfde als in [nuxt-12]:
/* eslint-disable no-console */
export default function(context) {
// wie voert deze code uit?
console.log('[middleware client], process.server', process.server, ', process.client=', process.client)
// beheer van de sessiecookie PHP in de browser
// de sessiecookie PHP van de browser moet identiek zijn aan die in de Nuxt-sessie
// de actie [fin-session] ontvangt een nieuwe cookie PHP (zowel de server als de Nuxt-client)
// als de server het ontvangt, moet de client het doorgeven aan de browser
// voor zijn eigen communicatie met de server PHP
// hier gaat het om client-routing
// we halen de sessiecookie op PHP
const phpSessionCookie = context.store.state.phpSessionCookie
if (phpSessionCookie) {
// indien aanwezig, wordt de sessiecookie PHP aan de browser toegewezen
document.cookie = phpSessionCookie
}
...
}
Om te voorkomen dat de klant naar niet-toegestane routes gaat, bieden we hem in het navigatiemenu voor klanten alleen de toegestane routes aan. De component [components/navigation] ziet er als volgt uit:
<template>
<!-- Bootstrap-menu met drie opties -->
<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>
- regel 4: de optie [Authentification] wordt alleen aangeboden als de sessie jSON is gestart, maar de gebruiker nog niet is geauthenticeerd. Als de sessie jSON niet is gestart of als de gebruiker al is geauthenticeerd, wordt de optie niet aangeboden;
- regels 7-11: de optie [Requête AdminData] wordt alleen aangeboden als de sessie jSON is gestart, de gebruiker is geauthenticeerd en de gegevens [AdminData] nog niet zijn opgehaald. Als aan een van deze drie voorwaarden niet is voldaan (sessie jSON niet gestart, gebruiker niet geauthenticeerd of de gegevens [AdminData] al opgehaald), wordt de optie niet aangeboden;
- regel 15: de optie [Fin session impôt] wordt aangeboden zodra de sessie jSON is gestart en de gebruiker is geauthenticeerd, anders niet;
16.3. Routering van de server [nuxt]
De routering van de server is over het algemeen complexer dan die van de client, omdat de gebruiker willekeurige URL-adressen in de adresbalk van zijn browser kan invoeren. We kunnen dit toestaan (de gebruiker hoort dit immers niet te doen) of proberen de zaken te controleren. Dat is wat we hier, ter illustratie, gaan doen, want in het geval van de applicatie [nuxt-12] kunnen we dit prima achterwege laten, aangezien de belastingberekeningsserver goed beveiligd is tegen dergelijke handmatig ingevoerde URL-adressen en de juiste foutmeldingen weet te versturen. Dat hebben we gezien in [next-12], waar er geen routeringscontrole was.
De routing van een [nuxt]-server verschilt sterk van die van een [nuxt]-client wat betreft het concept van omleiding:
- wanneer een [nuxt]-server wordt omgeleid, stuurt deze een omleidingsopdracht naar de clientbrowser met het doel van de omleiding. De browser doet vervolgens een nieuw verzoek aan de [nuxt]-server en vraagt om het doel dat aan hem is doorgegeven. Het is alsof de gebruiker het adres van de omleidingsbestemming handmatig had ingevoerd: de gehele URL-applicatie wordt opnieuw opgestart, en daarmee ook de volledige levenscyclus ervan (serverplugins, opslag, serverroutering, pagina’s);
- wanneer een client [nuxt] wordt omgeleid, gebeurt er niets van dit alles. Er vindt slechts een eenvoudige paginawisseling plaats, dezelfde als die zou zijn gebeurd als de gebruiker op een link had geklikt die naar het omleidingsdoel leidt. De levenscyclus is dan anders (clientroutering, weergave van het omleidingsdoel);
Om deze reden verdient het de voorkeur om client-routing te scheiden van server-routing, ook al lijken beide codes op elkaar.
Het routeringsscript van de server [middleware/server/routing] ziet er als volgt uit:
/* eslint-disable no-console */
export default function(context) {
// wie voert deze code uit?
console.log('[middleware server], process.server', process.server, ', process.client=', process.client)
// we halen wat informatie op uit de store [nuxt]
const store = context.store
// waar komen we vandaan?
const from = store.state.from || 'nowhere'
...
}
- bij de client-routing ontvangt de routingfunctie de context [context] met de eigenschap [context.from], wat de route is van de pagina waar men vandaan komt. De route waar men naartoe gaat, wordt verkregen via [context.route];
- bij serverrouting ontvangt de routeringsfunctie de context [context] zonder de eigenschap [context.from]. De serverroutering treedt alleen in werking wanneer een URL handmatig wordt opgevraagd bij de server [nuxt]. We weten dat dan de gehele applicatie [nuxt] wordt gereset. Het is alsof we helemaal opnieuw beginnen en er is dus geen sprake van een ‘vorige pagina’;
- dankzij de sessie [nuxt] weten we dat de server deze sessie kan ophalen en dus niet helemaal opnieuw hoeft te beginnen. Het is dus in deze sessie [nuxt], en meer bepaald in de store van deze sessie, dat we de naam zullen opslaan van de laatste pagina die door de clientbrowser werd weergegeven voordat een URL aan de server [nuxt] werd aangevraagd;
- regels 7-9: we halen de naam op van de laatste pagina die door de browser van de klant werd weergegeven. Bij het opstarten van de applicatie bestaat deze informatie [from] nog niet in de store. Vervolgens wordt de naam [nowhere] toegewezen aan de variabele [from];
Om ervoor te zorgen dat de server [nuxt] de naam van de laatst door de clientbrowser weergegeven pagina uit de store kan ophalen, moet de client [nuxt] deze informatie ook in de store opslaan. Het routeringsscript van de client [nuxt] wordt daarom als volgt aangevuld:
/* eslint-disable no-console */
export default function(context) {
// Wie voert deze code uit?
console.log('[middleware client], process.server', process.server, ', process.client=', process.client)
// Beheer van de sessiecookie PHP in de browser
// de sessiecookie PHP van de browser moet identiek zijn aan die in de Nuxt-sessie
// de actie [fin-session] ontvangt een nieuwe cookie PHP (zowel de server als de Nuxt-client)
// als de server het ontvangt, moet de client het doorgeven aan de browser
// voor zijn eigen communicatie met de server PHP
// hier gaat het om client-routing
// we halen de sessiecookie op PHP
const phpSessionCookie = context.store.state.phpSessionCookie
if (phpSessionCookie) {
// indien aanwezig, wordt de sessiecookie PHP aan de browser toegewezen
document.cookie = phpSessionCookie
}
// we slaan de naam van de pagina waarnaar we gaan op in de sessie – geen serveromleiding
context.store.commit('replace', { serverRedirection: false, from: context.route.name })
// de store wordt opgeslagen in de sessie [nuxt]
const session = context.app.$session()
session.value.store = context.store.state
session.save(context)
}
- de regels 19-24 worden toegevoegd;
- regel 20: de naam van de pagina [context.route.name] die zal worden weergegeven, wordt in de store geplaatst; deze pagina zal bij de volgende routering de pagina zijn waar we vandaan komen. Bovendien zullen we zien dat de server [nuxt] bij de routering moet weten of de huidige routering voortkomt uit een eerdere omleiding door de server [nuxt]. Dat is hier niet het geval, en daarom stellen we de eigenschap [serverRedirection] in op [false];
- regels 22-24: de status van de store wordt opgeslagen in de sessie [nuxt] (regel 23) en vervolgens wordt de sessie [nuxt] opgeslagen in een cookie (regel 24), die op zijn beurt wordt opgeslagen in de browser van de klant [nuxt];
Laten we teruggaan naar het routeringsscript van de server [nuxt]:
/* eslint-disable no-console */
export default function(context) {
// Wie voert deze code uit?
console.log('[middleware server], process.server', process.server, ', process.client=', process.client)
// we halen wat informatie op uit de store [nuxt]
const store = context.store
// waar komen we vandaan?
const from = store.state.from || 'nowhere'
// waar gaan we naartoe?
const to = context.route.name
// eventuele omleiding
let redirection = ''
// routering voltooid
let done = false
// bevinden we ons al in een omleiding van de server [nuxt]?
if (store.state.serverRedirection) {
// niets te doen
done = true
}
// Is dit een herlaadbeurt van de pagina?
if (to === from) {
// niets te doen
done = true
}
// controle van de navigatie van de server [nuxt]
// we baseren ons op de clientnavigatie in de component [navigation]
// geval waarin de sessie PHP niet is gestart
if (!done && !store.state.jsonSessionStarted && to !== 'index') {
// omleiding
redirection = 'index'
// taak voltooid
done = true
}
// in het geval dat de gebruiker niet is geauthenticeerd
if (!done && store.state.jsonSessionStarted && !store.state.userAuthenticated && to !== 'authentification') {
// omleiding
redirection = from
// taak voltooid
done = true
}
// geval waarin de gebruiker is geauthenticeerd
if (!done && store.state.jsonSessionStarted && store.state.userAuthenticated && to !== 'get-admindata' && to !== 'fin-session') {
// we blijven op dezelfde pagina
redirection = from
// taak voltooid
done = true
}
// geval waarin [adminData] is verkregen
if (!done && store.state.jsonSessionStarted && store.state.userAuthenticated && store.state.adminData && to !== 'fin-session') {
// blijft men op dezelfde pagina
redirection = from
// werk voltooid
done = true
}
// alle controles zijn uitgevoerd ---------------------
// omleiding?
if (redirection) {
// de omleiding wordt genoteerd in de store
store.commit('replace', { serverRedirection: true })
} else {
// geen omleiding
store.commit('replace', { serverRedirection: false, from: to })
}
// de store wordt opgeslagen in de sessie [nuxt]
const session = context.app.$session()
session.value.store = store.state
session.save(context)
// de eventuele omleiding wordt uitgevoerd
if (redirection) {
context.redirect({ name: redirection })
}
}
- regels 6-9: de waarde van [from] wordt opgehaald uit de store van de server [nuxt];
- regel 11: het doel van de huidige routering wordt genoteerd;
- regel 13: de routering kan leiden tot een omleiding van de browser van de klant. [redirection] is het doel van deze omleiding;
- regel 15: [done] naar [true] geeft aan dat de routering is voltooid;
- regels 17-21: er wordt eerst gekeken of de huidige routering voortkomt uit een omleidingsverzoek dat naar de browser van de klant is verzonden. Deze informatie is opgeslagen in de eigenschap [serverRedirection] van de store. Als deze eigenschap op ‘waar’ staat, betekent dit dat de server [nuxt] bij het vorige verzoek aan de server [nuxt] een omleiding naar de clientbrowser heeft verzonden. In dat geval hoeft er geen routering plaats te vinden. Bij het vorige verzoek heeft de router van de server [nuxt] besloten dat de clientbrowser moest worden omgeleid. Deze beslissing hoeft niet ter discussie te worden gesteld door een nieuwe routering;
- regels 23-27: er wordt gecontroleerd of de huidige routering een herlaadactie van de pagina is. Zo ja, dan wordt dit toegestaan;
- vanaf regel 29 worden de regels overgenomen die worden toegepast in de component [navigation] van de klant [nuxt] (zie vorige paragraaf);
- regels 32-38: hier wordt het geval behandeld waarin de sessie jSON niet is gestart en het routeringsdoel niet de pagina [index] is. In dat geval wordt de browser van de klant omgeleid naar de pagina [index];
- regels 40-46: hier wordt het geval behandeld waarin de sessie jSON is gestart, de gebruiker niet is geauthenticeerd en het doel van de huidige routering niet de pagina [authentification] is. In dit geval wordt de routering geweigerd en blijven we waar we waren;
- regels 48-54: we behandelen het geval waarin de sessie jSON is gestart, de gebruiker is geauthenticeerd en het doel van de huidige routering noch de pagina [get-admindata], noch de pagina [fin-session] is, die op dat moment de enige mogelijke bestemmingen zijn. In dit geval wordt de gevraagde routering geweigerd en keert men terug naar de vorige stap;
- regels 56-62: we behandelen het geval waarin [adminData] is verkregen. In dit geval is er slechts één mogelijke bestemming voor de omleiding: de pagina [fin-session]. Als dit niet de gevraagde pagina was, wordt de omleiding geweigerd en keert men terug naar de vorige stap;
- regels 64-72: als er een omleiding heeft plaatsgevonden, wordt dit genoteerd in de store van de server [nuxt]: [serverRedirection: true]. Merk op dat er geen waarde wordt toegekend aan de eigenschap [from] van de store. De reden hiervoor is dat er een omleiding vanuit de clientbrowser plaatsvindt en we hebben gezien dat er in dit geval geen routing plaatsvindt (regels 17-20) en dat de eigenschap [from] van de store niet wordt gebruikt;
- regels 66-69: als er geen omleiding plaatsvindt, wordt dit ook genoteerd in de store van de server [nuxt]: [serverRedirection: false]. Bovendien zal de huidige routing de pagina [to] weergeven, die voor het volgende verzoek (klant of server [nuxt]) de vorige pagina wordt. Daarom wordt [from: to] geschreven;
- regels 73-76: de store wordt opgeslagen in de sessie [nuxt], die zelf in een cookie is opgeslagen;
- regels 77-80: als [redirection] niet leeg is, wordt de browser gevraagd om door te sturen. Anders (wat hier niet te zien is) gaat de levenscyclus van de server [nuxt] verder: de pagina [to] wordt verwerkt door de server [nuxt] en verzonden naar de browser van de client [nuxt] met de sessiecookie [nuxt];
De hier gekozen routering voor de server [nuxt] is willekeurig. Men had ook een andere kunnen kiezen of, zoals gezegd, helemaal geen routering kunnen toepassen. De hierboven gekozen routering heeft als voordeel dat de applicatie altijd in een stabiele toestand blijft, ongeacht de door de gebruiker opgevraagde URL.
Er is één punt dat verbeterd kan worden wanneer de pagina die uiteindelijk wordt geladen de oorspronkelijke pagina is. Er zijn twee gevallen:
- de gebruiker heeft ervoor gezorgd dat de pagina opnieuw wordt geladen (to===from);
- er zijn omleidingen naar de oorspronkelijke pagina (redirection===from);
In beide gevallen wordt de oorspronkelijke pagina opnieuw uitgevoerd met de asynchrone aanroep naar de server voor de belastingberekening. Laten we een voorbeeld nemen. Stel dat de gebruiker, nadat hij is geauthenticeerd, de pagina opnieuw laadt (F5). In dat geval geldt in de bovenstaande routing: [to]=[from]=[authentification]. Er vindt geen omleiding plaats. De pagina [to=authentification] wordt uitgevoerd door de server [nuxt]. Als er niets wordt gedaan, wordt de functie [asyncData] opnieuw uitgevoerd. Dit is overbodig, aangezien de authenticatie al heeft plaatsgevonden.
We kunnen dit verbeteren door de pagina [authentification] enigszins aan te passen:
// asynchrone gegevens
async asyncData(context) {
// log
console.log('[authentification asyncData started]')
// we doen dingen niet twee keer als de pagina al is opgevraagd
if (process.server && context.store.state.userAuthenticated) {
console.log('[authentification asyncData canceled]')
return { result: '[succès]' }
}
// client [nuxt]
if (process.client) {
// begin wachtrij
context.app.$eventBus().$emit('loading', true)
// geen fout
context.app.$eventBus().$emit('errorLoading', false)
}
try {
// we verifiëren ons bij de server
...
- regels 6-9: als de pagina wordt uitgevoerd door de server [nuxt] en we in de store ontdekken dat de authenticatie al heeft plaatsgevonden, dan geven we direct het gewenste resultaat terug (regel 8);
Hetzelfde geldt voor alle pagina's:
Pagina [index]:
// asynchrone gegevens
async asyncData(context) {
// log
console.log('[index asyncData started]')
// we doen dingen niet twee keer als de pagina al is opgevraagd
if (process.server && context.store.state.jsonSessionStarted) {
console.log('[index asyncData canceled]')
return { result: '[succès]' }
}
try {
...
Pagina [get-admindata]
// asynchrone gegevens
async asyncData(context) {
// log
console.log('[get-admindata asyncData started]')
// we doen dingen niet twee keer als de pagina al is opgevraagd
if (process.server && context.store.state.adminData) {
console.log('[get-admindata asyncData canceled]')
return { result: context.store.state.adminData }
}
// client
if (process.client) {
// begin wachttijd
context.app.$eventBus().$emit('loading', true)
// geen fout
context.app.$eventBus().$emit('errorLoading', false)
}
try {
...
Pagina [fin-session]
// asynchrone gegevens
async asyncData(context) {
// log
console.log('[fin-session asyncData started]')
// we doen dingen niet twee keer als de pagina al is opgevraagd
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)." }
}
// geval van de klant [nuxt]
if (process.client) {
// begin wachtrij
context.app.$eventBus().$emit('loading', true)
// geen fout
context.app.$eventBus().$emit('errorLoading', false)
}
try {
16.4. Exécution
Om dit voorbeeld uit te voeren, moet u ervoor zorgen dat u vóór de uitvoering de sessiecookie [nuxt] en de cookie PHP verwijdert uit de browser waarin de client [nuxt] wordt uitgevoerd, zodat u vanuit een schone situatie begint. Hieronder volgt een voorbeeld met de Chrome-browser:

16.5. Conclusion
De routering van de server [nuxt] is complex, omdat rekening moet worden gehouden met alle URL-waarden die de gebruiker handmatig kan invoeren. Dit is een schoolvoorbeeld. Een applicatie [nuxt] is niet bedoeld om op deze manier te worden gebruikt. Zodra de pagina [index] door de router van de server [nuxt] is geleverd, zouden de volgende verzoeken aan de server kunnen worden omgeleid naar een foutpagina.
In het specifieke geval van ons voorbeeld [nuxt-13] was de routering van de server [nuxt] overbodig. De standaardroutering (in feite geen routering) in het voorbeeld [nuxt-12] voldeed prima.