8. Beispiel [nuxt-05]: Persistenz des Stores mit einem Session-Cookie
Ziel: Wir möchten, dass der [Vuex]-Store nicht bei jeder Anfrage an den Server zurückgesetzt wird. Um dies zu erreichen, verwenden wir ein Session-Cookie:
- Der Store wird vom Server initialisiert und von diesem in einem Session-Cookie gespeichert;
- der Client-Browser erhält dieses Session-Cookie und sendet es automatisch mit jeder neuen Anfrage an den Server;
- der Server kann dieses Session-Cookie dann abrufen und mit dem darin enthaltenen Store arbeiten, einem vom Client aktualisierten Store;
8.1. Übersicht
Das Projekt [nuxt-05] wird zunächst durch Klonen des Projekts [nuxt-04] erstellt:

Wir werden sehen, dass sich nur die Datei [store/index.js] ändern wird.
Um Cookies mit [nuxt] zu verwenden, nutzen wir das Modul [cookie-universal-nuxt], das wir mit [yarn] in einem VSCode-Terminal installieren:

- Geben Sie in [4] den Befehl [yarn add cookie-universal-nuxt] ein;
Dadurch wird ein neues Modul zur Datei [package.json] des [dvp]-Projekts hinzugefügt:
...
},
"dependencies": {
"@nuxtjs/axios": "^5.3.6",
"bootstrap": "^4.1.3",
"bootstrap-vue": "^2.0.0",
"cookie-universal-nuxt": "^2.0.19",
"nuxt": "^2.0.0"
},
8.2. Die Konfigurationsdatei [nuxt.config.js]
Damit [nuxt] Cookies von [cookie-universal-nuxt] verwenden kann, müssen Sie dieses Modul in der Konfigurationsdatei [nuxt.config.js] deklarieren:
...
],
/*
** Nuxt.js modules
*/
modules: [
// Doc: https://bootstrap-vue.js.org
'bootstrap-vue/nuxt',
// Doc: https://axios.nuxtjs.org/usage
'@nuxtjs/axios',
// https://www.npmjs.com/package/cookie-universal-nuxt
'cookie-universal-nuxt'
],
...
- Zeile 12: Das Modul [cookie-universal-nuxt] wird dem Modul-Array [nuxt] hinzugefügt [6];
Die Datei [nuxt.config.js] sieht letztendlich wie folgt aus:
export default {
mode: 'universal',
/*
** Headers of the page
*/
head: {
title: 'Introduction à [nuxt.js]',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{
hid: 'description',
name: 'description',
content: 'ssr routing loading asyncdata middleware plugins store'
}
],
link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }]
},
/*
** Customize the progress-bar color
*/
loading: { color: '#fff' },
/*
** Global CSS
*/
css: [],
/*
** Plugins to load before mounting the App
*/
plugins: [],
/*
** Nuxt.js dev-modules
*/
buildModules: [
// Doc: https://github.com/nuxt-community/eslint-module
'@nuxtjs/eslint-module'
],
/*
** Nuxt.js modules
*/
modules: [
// Doc: https://bootstrap-vue.js.org
'bootstrap-vue/nuxt',
// Doc: https://axios.nuxtjs.org/usage
'@nuxtjs/axios',
// https://www.npmjs.com/package/cookie-universal-nuxt
'cookie-universal-nuxt'
],
/*
** Axios module configuration
** See https://axios.nuxtjs.org/options
*/
axios: {},
/*
** Build configuration
*/
build: {
/*
** You can extend webpack config here
*/
extend(config, ctx) {}
},
// source code directory
srcDir: 'nuxt-05',
// router
router: {
// application URL root
base: '/nuxt-05/'
},
// server
server: {
// service port, default 3000
port: 81,
// network addresses listened to, default localhost: 127.0.0.1
// 0.0.0.0 = all the machine's network addresses
host: 'localhost'
},
// environment
env: {
maxAge: 60 * 5
}
}
- Zeile 79: Wir haben den Schlüssel [env] zur Datei hinzugefügt. Dieser Schlüssel ist ein reserviertes Wort. Die in diesem Objekt deklarierten Elemente sind über das Objekt [context.env] in den Elementen der Anwendung verfügbar;
- Zeile 80: Das Attribut [maxAge] gibt die maximale Lebensdauer des Session-Cookies an, gemessen ab dem Zeitpunkt der letzten Initialisierung des Cookies. Diese Dauer wird in Sekunden angegeben. Hier haben wir eine Lebensdauer von 5 Minuten festgelegt;
8.3. Das Prinzip der Speicherpersistenz
Cookies, die zwischen dem Client und dem Server ausgetauscht werden, sind auf beiden Seiten (Client und Server) verfügbar in:
- [context.app.$cookies], wo immer das [context]-Objekt verfügbar ist, d. h. fast überall;
- [this.$cookies] innerhalb einer Ansicht;
Ein bestimmtes Cookie wird mit dem Ausdruck [...$cookies.get('cookie_name')] abgerufen. Der Wert eines Cookies wird mit dem Ausdruck [...$cookies.set('cookie_name', cookie_value)] gesetzt.
Das Prinzip hinter dem Persistenz-Cookie des Stores ist wie folgt:
- Wenn der Server den Store in der Funktion [nuxtServerInit] initialisiert, wird der Zustand des Stores in einem Cookie namens „session“ gespeichert;
- Das „session“-Cookie ist dann Teil der HTTP-Antwort des Servers. Wir wissen, dass ein Browser die Cookies, die der Server ihm gesendet hat, an den Server zurücksendet. Dies geschieht bei jeder neuen Anfrage, die er an den Server stellt. Wir wissen auch, dass der Server den Store innerhalb der Seite sendet, die er an den Client übermittelt;
- Im Browser ruft die Client-Anwendung den vom Server gesendeten Store ab und führt dann ihre Aufgaben aus. Wir stellen sicher, dass bei jeder Änderung des Stores dessen neuer Zustand in dem vom Browser gespeicherten „session“-Cookie gespeichert wird;
- Wenn der Benutzer eine Anfrage an den Server erzwingt, sendet der Client-Browser automatisch alle Cookies zurück, die der Server zuvor an ihn gesendet hat, einschließlich des Cookies mit dem Namen „session“;
- Wenn der Server nach dieser Anfrage den Speicher erneut zurücksetzt, ruft er das „Session“-Cookie ab und initialisiert den Zustand des Speichers mit dessen Wert;
- Dadurch wird die Kontinuität des Speichers zwischen Client und Server gewährleistet;
8.4. Initialisierung des Speichers
Der Speicher ist in der Datei [store / index.js] implementiert:
/* eslint-disable no-console */
export const state = () => ({
// meter
counter: 0
})
export const mutations = {
// increment counter by one [inc] value
increment(state, inc) {
state.counter += inc
},
// state replacement
replace(state, newState) {
for (const attr in newState) {
state[attr] = newState[attr]
}
}
}
export const actions = {
async nuxtServerInit(store, context) {
// who executes this code?
console.log('nuxtServerInit, client=', process.client, 'serveur=', process.server, 'env=', context.env)
// waiting for a promise to be fulfilled
await new Promise(function(resolve, reject) {
// this is normally an asynchronous function
// we simulate it with a one-second wait
setTimeout(() => {
// init session
initStore(store, context)
// success
resolve()
}, 1000)
})
}
}
function initStore(store, context) {
// is there a session cookie in the current request?
const cookies = context.app.$cookies
const session = cookies.get('session')
if (!session) {
// no existing session
console.log("nuxtServerInit, initialisation d'une nouvelle session")
// initialize the blind
store.commit('increment', 77)
} else {
console.log("nuxtServerInit, reprise d'une session existante")
// update the store with the session cookie
store.commit('replace', session.store)
}
// put the store in the session cookie
cookies.set('session', { store: store.state }, { path: context.base, maxAge: context.env.maxAge })
// log
console.log('initStore terminé, store=', store.state)
}
Kommentare
- Zeilen 2–5: Der Laden wird aus einer Theke bestehen;
- Zeilen 9–11: Dieser Zähler kann erhöht werden;
- Zeilen 13–17: Der Zustand des Stores kann aus einem neuen Zustand initialisiert werden. Diese Funktion dient dazu, eine mögliche Initialisierung des Stores zu veranschaulichen, wenn dieser nicht wie in diesem Beispiel auf einen Zähler beschränkt ist;
- Zeilen 21–35: Die Funktion [nuxtServerInit] hat sich nicht geändert;
- Zeile 30: Nach Ablauf der einsekündigen Zeitüberschreitung wird der Speicher mithilfe der Funktion in den Zeilen 38–56 initialisiert;
- Zeilen 40–41: Zunächst rufen wir das Cookie mit dem Namen „session“ ab:
- Bei der ersten Ausführung der Anwendung und bei der ersten Anfrage an den Server existiert dieses Cookie noch nicht. Es wird dann erstellt (Zeile 53) und an den Browser des Clients gesendet;
- Während derselben Ausführung der Anwendung und bei den Anfragen Nr. 2, Nr. 3, ... an den Server existiert dieses Cookie, da der Browser des Clients es bei jeder neuen Anfrage an den Server zurücksendet;
- Bei einer zweiten Ausführung der Anwendung und bei der ersten Anfrage an den Server kann dieses Cookie ebenfalls vorhanden sein. Tatsächlich wurde das Cookie am Ende von Schritt 1 mit einer bestimmten Lebensdauer im Browser gespeichert. Wenn diese Lebensdauer noch nicht abgelaufen ist, wird das Cookie mit dem Namen „session“ mit der ersten Anfrage an den Server gesendet
Zusammenfassend lässt sich sagen: Bei jeder Anfrage an den Server gilt: Wenn das „session“-Cookie bereits im Browser des Clients gespeichert ist, erhält der Server es; andernfalls nicht.
- Zeilen 42–47: Wenn der Server das Session-Cookie nicht erhält, wird der Speicher in Zeile 46 initialisiert;
- anschließend wird in Zeile 53 ein Cookie namens „session“ erstellt und in die HTTP-Antwort des Servers eingefügt. Der Wert des Cookies ist das Objekt [{ store: store.state }]. Es ist also der Zustand des Speichers und nicht der Speicher selbst, der in das Session-Cookie eingefügt wird;
- der dritte Parameter der [set]-Funktion ist ein Optionsobjekt:
- [path] gibt die URL an, an die dieses Cookie gesendet werden soll. [context.base] ist die Basis-URL der [nuxt-05]-Anwendung. Diese ist in der Datei [nuxt.config.js] definiert:
// router
router: {
// application URL root
base: '/nuxt-05/'
},
- [maxAge] ist die Lebensdauer des Cookies in Sekunden im Browser. Nach Ablauf dieser Zeit sendet der Browser es nicht mehr an den Server zurück. [context.env.maxAge] gibt einen Wert zurück, der in der Datei [nuxt.config.js] festgelegt ist:
[env] ist ein reserviertes Schlüsselwort in der Konfigurationsdatei. Hier legen wir die Lebensdauer auf 5 Minuten fest. Diese Dauer wird ab dem Zeitpunkt gemessen, zu dem der Browser das Sitzungscookie zuletzt erhalten hat. Nach Ablauf dieser Zeit wird das Cookie nicht mehr an den Server zurückgesendet, der dann eine neue Sitzung starten muss;
- Zeilen 48–50: Wenn der Server das Sitzungscookie empfängt, wird der Zustand des Stores mit dem [store]-Objekt aus dem Sitzungscookie initialisiert. Zur Erinnerung: Dieses Objekt enthält den gespeicherten Zustand des Stores;
- Anschließend wird in Zeile 53 das Sitzungscookie in die an den Browser des Clients gesendete Antwort eingefügt:
- Die Funktion [get] ruft das Sitzungscookie aus der vom Server empfangenen Anfrage ab;
- Die Funktion [set] fügt das Sitzungs-Cookie in die Antwort ein, die der Server an den Browser des Clients sendet;
- Anschließend wird in Zeile 53 das Sitzungscookie in die an den Browser des Clients gesendete Antwort eingefügt:
8.5. Erhöhen des Store-Zählers
Die Zählerstandserhöhung auf der Seite [index.vue] funktioniert wie folgt:
// event management
methods: {
incrementCounter() {
console.log('incrementCounter')
// counter increment of 1
this.$store.commit('increment', 1)
// change display value
this.value = this.$store.state.counter
// store in session cookie
this.$cookies.set('session', { store: this.$store.state }, { path: this.$nuxt.context.base, maxAge: this.$nuxt.context.env.maxAge })
}
}
Auf der Client-Seite muss der Store bei jeder Änderung im Session-Cookie gespeichert werden. Der Grund dafür ist, dass der Benutzer jederzeit manuell eine URL anfordern kann und wir dann in der Lage sein müssen, einen aktuellen Store an den Server zu senden. Deshalb speichern wir in Zeile 10, nachdem wir den Store-Zähler erhöht haben, dessen Zustand im Session-Cookie:
- Cookies sind in der Eigenschaft [this.$cookies] verfügbar;
- der Zustand des Stores [this.$store.state] wird in dem Cookie gespeichert, das mit dem Schlüssel [store] verknüpft ist;
- der Cookie-Pfad lautet [context.base]. In einer Ansicht ist der Kontext in [this.$nuxt.context] verfügbar;
- Die Lebensdauer des Cookies beträgt [context.env.maxAge], was hier in der Eigenschaft [this.$nuxt.context.env.maxAge] verfügbar ist;
8.6. Ausführen des Beispiels [nuxt-05]
Wir starten die Anwendung [nuxt-05]:

Die folgenden Screenshots stammen aus dem Chrome-Browser. Wir rufen die URL [http://localhost:81/nuxt-05/] auf. Vergessen Sie nicht das abschließende „/“ nach „/nuxt-05“, da Sie sonst nicht die erwarteten Ergebnisse erhalten:

- In [4] haben wir den Anfangswert des Stores (77) erhalten;
Sehen wir uns die Browser-Protokolle an (F12):

- in [5-6] die Serverprotokolle;
- in [7] sehen wir, dass der Server eine neue Sitzung startet. Das bedeutet, dass er kein Sitzungscookie erhalten hat;
- in [8] die Initialisierung des Zählers mit dem Wert 77;
- in [9] zeigen sowohl die [index]-Seite des Servers (9) als auch die [index]-Seite des Clients (10) denselben Zählerwert an;
Sehen wir uns nun die vom Browser empfangenen Cookies an:

- Wählen Sie in [1] die Registerkarte [Anwendung] und dann die Option [Cookies] [2]. Wählen Sie aus allen Cookies in Ihrem Browser dasjenige aus der Domain [http://localhost:81] aus;
- in [4] das Cookie mit dem Namen „session“. Wenn Sie es nicht sehen, laden Sie die Seite neu [F5]: Möglicherweise ist seine Lebensdauer von 5 Minuten abgelaufen;
- in [5] den Wert des Cookies. Obwohl er aufgrund der Kodierung der Zeichen { : nicht sehr gut lesbar ist, können Sie den Wert 77 aus dem Zähler erkennen;
- in [6] die URL des Cookies: Jedes Mal, wenn diese URL angefordert wird, sendet der Browser das Cookie an den Server;
- in [7] die Ablaufzeit des Cookies. Sobald diese Zeit abgelaufen ist, wird das Cookie aus dem Browser gelöscht;
Stellen Sie sicher, dass Sie dieses Cookie haben. Falls nicht, laden Sie die Seite neu (F5). Sobald Sie die Seite mit dem Cookie haben, laden Sie die Seite erneut (F5). Die Protokolle sehen dann wie folgt aus:

Diesmal hat der Server in [3] das Sitzungs-Cookie erfolgreich abgerufen. Es wurde ihm vom Client-Browser gesendet.
Erhöhen Sie nun den Zähler und laden Sie die aktuelle Seite gelegentlich neu (F5) – egal, ob es sich um [index] oder [page1] handelt – und Sie sollten feststellen, dass der Zähler nicht wie im Beispiel [nuxt-04] auf 77 zurückgesetzt wird, sondern den Wert beibehält, den er im Client-Browser vor dem Neuladen der Seite hatte:


Die Browser-Protokolle sehen dann wie folgt aus:

Hinweis: Zu Testzwecken müssen Sie möglicherweise [5] das im Browser gespeicherte Sitzungscookie löschen, um bei der nächsten Anfrage an den Server eine neue, vom Server initiierte Sitzung zu starten.
Abschließend wollen wir die Auswirkung der Funktion [incrementCounter] auf der Seite [index] auf das im Browser des Clients gespeicherte Sitzungscookie demonstrieren:
// event management
methods: {
incrementCounter() {
console.log('incrementCounter')
// counter increment of 1
this.$store.commit('increment', 1)
// change display value
this.value = this.$store.state.counter
// store in session cookie
this.$cookies.set('session', { store: this.$store.state }, { path: this.$nuxt.context.base, maxAge: this.$nuxt.context.env.maxAge })
}
}
- Zeile 10: Die Änderung am Zähler wird im Session-Cookie gespeichert;
Lassen Sie uns dies überprüfen. Wir beginnen mit der folgenden Situation:

- In [4] spiegelt der Zähler des Sitzungs-Cookies korrekt den angezeigten Wert [1] wider;
Erhöhen wir nun den Zähler um eins [5]. Das Session-Cookie in [4] ändert sich wie folgt:

- In [7] hat sich der Zählwert des Session-Cookies tatsächlich auf 84 geändert. Um dies zu sehen, müssen Sie die Ansicht aktualisieren [8]. Wählen Sie dazu eine andere Option unter [Speicher] [9] aus und wählen Sie anschließend die Option [8] erneut aus. Der neue Wert des Session-Cookies sollte dann angezeigt werden;