Skip to content

15. Beispiel [nuxt-12]: Anfragen an HTTP mit axios

15.1. Présentation

In diesem neuen Beispiel werden wir sehen, wie man in den Funktionen [asyncData] Anfragen an HTTP mit der Bibliothek [axios] stellen kann. Außerdem werden wir bereits erlernte Konzepte anwenden:

  • die Verwendung von Plugins aus dem Beispiel [nuxt-06]:
  • die Speicherung des Stores in einem Session-Cookie aus dem Beispiel [nuxt-06];
  • die Steuerung der Navigation mit Middlewares aus dem Beispiel [nuxt-09];
  • die Fehlerbehandlung aus dem Beispiel [nuxt-11];

Die Architektur des Beispiels sieht wie folgt aus:

Image

  • Die Anwendung [nuxt] wird auf dem Server [node.js] [3] gespeichert, vom Browser [1] heruntergeladen und anschließend von diesem ausgeführt;
  • Sowohl der Client [nuxt] [1] als auch der Server [nuxt] [3] werden Anfragen an den Datenserver [2]. Dieser Server ist der in Abschnitt PHP 7 entwickelte Steuerberechnungsserver. Wir verwenden dessen neueste Version, Version 14, mit den zugelassenen Anfragen CORS;

Die Architektur des Beispiels lässt sich wie folgt vereinfachen:

Image

  • In [1] liefert der Server [node.js] die Seiten [nuxt] an den Browser [2]. Es ist die Schicht [web] [8] des Servers, die diese Seiten bereitstellt. Um die Seite bereitzustellen, hat der Server möglicherweise externe Daten vom Datenserver [3] angefordert. Die Schicht [DAO] [9] führt die erforderlichen Anfragen HTTP durch;
  • bei jedem Seitenaufruf an den Server [node.js][1] erhält der Browser [2] die gesamte Anwendung [nuxt], die dann im Modus SPA ausgeführt wird. Der Block [UI] (Benutzeroberfläche) [4] zeigt dem Benutzer Seiten [vue.js] an. Die Aktionen des Benutzers oder der natürliche Lebenszyklus der Seiten können dazu führen, dass externe Daten vom Datenserver [3] abgerufen werden. Die Schicht [DAO] [5] führt dann die erforderlichen Abfragen HTTP durch;

15.2. Projektstruktur

Image

15.3. Die Konfigurationsdatei [nuxt.config.js]

Das Projekt wird anhand der folgenden Datei „[nuxt.config.js]“ geprüft:


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: false,

  /*
   ** Global CSS
   */
  css: [],
  /*
   ** Plugins to load before mounting the App
   */
  plugins: [
    { src: '@/plugins/client/plgSession', mode: 'client' },
    { src: '@/plugins/server/plgSession', mode: 'server' },
    { src: '@/plugins/client/plgDao', mode: 'client' },
    { src: '@/plugins/server/plgDao', mode: 'server' },
    { src: '@/plugins/client/plgEventBus', mode: 'client' }
  ],
  /*
   ** Nuxt.js dev-modules
   */
  buildModules: [
    // Dok.: https://github.com/nuxt-community/eslint-module
    '@nuxtjs/eslint-module'
  ],
  /*
   ** Nuxt.js modules
   */
  modules: [
    // Dok.: https://bootstrap-vue.js.org
    'bootstrap-vue/nuxt',
    // Dok.: 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) { }
  },
  // Quellcode-Verzeichnis
  srcDir: 'nuxt-12',
  // Router
  router: {
    // Stammverzeichnis der Anwendung URL
    base: '/nuxt-12/',
    // Routing-Middleware
    middleware: ['routing']
  },
  // Server
  server: {
    // Dienstport, standardmäßig 3000
    port: 81,
    // Abgehörte Netzwerkadressen, standardmäßig localhost: 127.0.0.1
    // 0.0.0.0 = alle Netzwerkadressen des Rechners
    host: 'localhost'
  },
  // Umgebung
  env: {
    // Axios-Konfiguration
    timeout: 2000,
    withCredentials: true,
    baseURL: 'http://„localhost/php7/scripts-web/impots/version-14“,
    // Konfiguration des Sitzungs-Cookies [nuxt]
    maxAge: 60 * 5
  }
}
  • Zeile 22: Wir verwalten die Benachrichtigung über das Warten auf das Ende einer asynchronen Aktion selbst;
  • Zeile 31: Wir werden verschiedene Plugins verwenden, die entweder für den Client oder für den Server spezialisiert sind, jedoch nicht für beide gleichzeitig;
  • Zeile 52: Das Modul [axios] ist in [nuxt] integriert. Dies hat zur Folge, dass das Objekt [axios], das die Anfragen HTTP derAnwendung [nuxt] an den Steuerberechnungsserver PHP sendet, in [context.$axios] verfügbar sein wird;
  • Zeile 54: Das Modul [cookie-universal-nuxt] ermöglicht es uns, die Sitzung [nuxt] in einem Cookie zu speichern;
  • Zeile 60: Mit der Eigenschaft [axios] können wir das Modul [@nuxtjs/axios] aus Zeile 52 konfigurieren. Wir werden diese Möglichkeit jedoch nicht nutzen, sondern stattdessen die Eigenschaft [env] aus Zeile 88 bevorzugen;
  • Zeile 90: Maximale Wartezeit auf die Antwort des Steuerberechnungsservers;
  • Zeile 91: erforderlich für den Client [nuxt] – erlaubt die Verwendung von Cookies beim Datenaustausch mit dem Steuerberechnungsserver;
  • Zeile 92: Basis-URL des Steuerberechnungsservers;
  • Zeile 94: Lebensdauer der Nuxt-Sitzung (5 Minuten);
  • Zeile 77: Die Kommunikation zwischen Client und Server [nuxt] wird durch eine Routing-Middleware gesteuert;

15.4. Die [UI]-Schicht der Anwendung

Image

Wir werden der Anwendung [nuxt] über die folgende Ansicht Zugriff auf die API des Steuerberechnungsservers gewähren:

Image

  • in [2] das Menü, das den Zugriff auf die Seite API des Steuerberechnungsservers ermöglicht:
    • [Authentification]: entspricht der Seite [authentification]. Diese Seite sendet eine Authentifizierungsanfrage an den Steuerberechnungsserver mit den Anmeldedaten [admin, admin], die derzeit als einzige zugelassen sind. Das angezeigte Ergebnis entspricht dem von [3];
    • [Requête AdminData]: entspricht der Seite [get-admindata]. Diese Seite fordert vom Steuerberechnungsserver die Daten an, die hier als [adminData] bezeichnet werden und die Berechnung der Steuer ermöglichen. Das angezeigte Ergebnis entspricht dem von [3];
    • [Fin session impôt]: entspricht der Seite [fin-session]. Diese Seite sendet eine Anfrage zum Beenden der Sitzung PHP an den Steuerberechnungsserver. Der Server bricht daraufhin die aktuelle Sitzung PHP ab und initialisiert eine neue, leere Sitzung;

15.5. Die Schichten [dao] der Anwendung [nuxt]

Wie oben erwähnt, wird die Architektur der Anwendung [nuxt] wie folgt aussehen:

Image

  • In [1] liefert der Server [node.js] die Seiten [nuxt] an den Browser [2]. Es ist die Schicht [web] [8] des Servers, die diese Seiten bereitstellt. Um die Seite bereitzustellen, hat der Server möglicherweise externe Daten vom Datenserver [3] angefordert. Die Schicht [DAO] [9] führt die erforderlichen Anfragen HTTP durch;
  • bei jedem Seitenaufruf an den Server [node.js][1] erhält der Browser [2] die gesamte Anwendung [nuxt], die dann im Modus SPA ausgeführt wird. Der Block [UI] (Benutzeroberfläche) [4] zeigt dem Benutzer Seiten [vue.js] an. Die Aktionen dieses Blocks oder der Lebenszyklus der Seiten können zu externen Datenaufrufen an den Datenserver [3] führen. Die Schicht [DAO] [5] führt dann die erforderlichen Abfragen HTTP durch;

Wir verwenden die Version 14 des Steuerberechnungsservers, der im Dokument |Einführung in die Sprache PHP7 anhand eines Beispiels| entwickelt wurde. Wir nutzen nur einen Teil seiner API (Application Programming Interface) jSON:

Anfrage
Antwort
1
2
3
4
5
6
[initialisation d’une session jSON avec le
serveur de calcul de l’impôt]
[une session PHP est créée avec le serveur de
calcul de l’impôt]

GET main.php?action=init-session&type=json

{
    "action": "init-session",
    "état"700,
    "réponse": "session démarrée avec type [json]"
}

[authentification de l’utilisateur]
[l’authentification est stockée dans la
session PHP]

POST main.php?action=authentifier-utilisateur
paramètres postés : user, admin

{
    "action": "authentifier-utilisateur",
    "état"200,
    "réponse": "Authentification réussie [admin, admin]"
}

[demande des données de l’administration
fiscale]
[les données reçues sont stockées dans la
session PHP]

GET main.php?action=get-admindata

{
    "action": "get-admindata",
    "état"1000,
    "réponse": {
        "limites": [
            9964,
            27519,
            73779,
            156244,
            0
        ],
        "coeffR": [
            0,
            0.14,
            0.3,
            0.41,
            0.45
        ],
        "coeffN": [
            0,
            1394.96,
            5798,
            13913.69,
            20163.45
        ],
        "plafondQfDemiPart": 1551,
        "plafondRevenusCelibatairePourReduction": 21037,
        "plafondRevenusCouplePourReduction": 42074,
        "valeurReducDemiPart": 3797,
        "plafondDecoteCelibataire": 1196,
        "plafondDecoteCouple": 1970,
        "plafondImpotCouplePourDecote": 2627,
        "plafondImpotCelibatairePourDecote": 1595,
        "abattementDixPourcentMax": 12502,
        "abattementDixPourcentMin": 437
    }
}

[fin de la session PHP avec le serveur de
calcul de l’impôt]
[supprime la session PHP courante et crée une
nouvelle session PHP. Dans celle-ci, la
session jSON reste activée, mais l’utilisateur
n’est plus authentifié]

GET main.php?action=fin-session

{
    "action": "fin-session",
    "état"400,
    "réponse": "session supprimée"
}

15.5.1. Die Ebene [dao] des Servers [nuxt]

Image

Der Server [node.js] [1] wird die Schicht [dao] verwenden, die im Dokument |Einführung in das Framework VUE.JS anhand eines Beispiels| beschrieben ist. Hier noch einmal der Code:


'use strict';

// Importe
import qs from 'qs'

class Dao {

  // Konstruktor
  constructor(axios) {
    this.axios = axios;
    // Sitzungs-Cookie
    this.sessionCookieName = "PHPSESSID";
    this.sessionCookie = '';
  }

  // Sitzung initialisieren
  async  initSession() {
    // Anfrageoptionen HHTP [get /main.php?action=init-session&type=json]
    const options = {
      method: "GET",
      // Parameter der Abfrage URL
      params: {
        action: 'init-session',
        type: 'json'
      }
    };
    // Ausführung der Abfrage HTTP
    return await this.getRemoteData(options);
  }

  async  authentifierUtilisateur(user, password) {
    // Optionen der Abfrage HHTP [post /main.php?action=authentifier-utilisateur]
    const options = {
      method: "POST",
      headers: {
        'Content-Type: 'application/x-www-form-urlencoded',
      },
      // Hauptteil des POST
      data: qs.stringify({
        user: user,
        password: password
      }),
      // Parameter der URL
      params: {
        action: 'authentifier-utilisateur'
      }
    };
    // Ausführung der Abfrage HTTP
    return await this.getRemoteData(options);
  }

  async getAdminData() {
    // Optionen der Abfrage HHTP [get /main.php?action=get-admindata]
    const options = {
      method: "GET",
      // Parameter der Abfrage URL
      params: {
        action: 'get-admindata'
      }
    };
    // Ausführung der Abfrage HTTP
    const data = await this.getRemoteData(options);
    // Ergebnis
    return data;
  }

  async  getRemoteData(options) {
    // für das Sitzungs-Cookie
    if (!options.headers) {
      options.headers = {};
    }
    options.headers.Cookie = this.sessionCookie;
    // Ausführung der Anfrage HTTP
    let response;
    try {
      // asynchrone Anfrage
      response = await this.axios.request('main.php', options);
    } catch (error) {
      // Der Parameter [error] ist eine Ausnahmeinstanz – er kann verschiedene Formen annehmen
      if (error.response) {
        // Die Antwort des Servers befindet sich in [error.response]
        response = error.response;
      } else {
        // Der Fehler wird erneut ausgelöst
        throw error;
      }
    }
    // „response“ ist die gesamte Antwort HTTP des Servers (Header HTTP + die Antwort selbst)
    // Das Sitzungs-Cookie wird abgerufen, sofern es vorhanden ist
    const setCookie = response.headers['set-cookie'];
    if (setCookie) {
      // setCookie ist ein Array
      // Das Session-Cookie wird in diesem Array gesucht
      let trouvé = false;
      let i = 0;
      while (!trouvé && i < setCookie.length) {
        // Das Session-Cookie wird gesucht
        const results = RegExp('^(' + this.sessionCookieName + '.+?);').exec(setCookie[i]);
        if (results) {
          // Das Session-Cookie wird gespeichert
          // eslint-disable-next-line require-atomic-updates
          this.sessionCookie = results[1];
          // Es wurde gefunden
          trouvé = true;
        } else {
          // nächstes Element
          i++;
        }
      }
    }
    // Die Antwort des Servers lautet: [response.data]
    return response.data;
  }
}

// Export der Klasse
export default Dao;
  • Alle Methoden der Schicht [dao] geben das vom Datenserver [{action : ‘xx’, état : nn, réponse : {...}] gesendete Objekt mit folgenden Parametern zurück:
    • [action]: Name der vom Datenserver ausgeführten Aktion;
    • [état]: numerischer Indikator:
      • [initSession]: Status=700 für eine fehlerfreie Antwort;
      • [authentifierUtilisateur]: Status=200 für eine fehlerfreie Antwort;
      • [getAdminData]: Status=1000 für eine fehlerfreie Antwort;
      • [fin-session]: Status=400 für eine fehlerfreie Antwort;
    • [réponse]: Antwort, die mit dem numerischen Indikator [état] verknüpft ist. Kann je nach diesem numerischen Indikator variieren;

Betrachten wir den Konstruktor der Klasse [Dao]:


// Konstruktor
  constructor(axios) {
    this.axios = axios;
    // Sitzungs-Cookie
    this.sessionCookieName = "PHPSESSID";
    this.sessionCookie = '';
}
  • Zeile 2: Das Objekt [axios], das als Argument an den Konstruktor übergeben wird, wird vom aufrufenden Code bereitgestellt. Es ist dieses Objekt, das die Anfragen HTTP ausführt;
  • Zeile 5: Der Name des vom Datenserver gesendeten Sitzungs-Cookies, geschrieben als PHP;
  • Zeile 6: Das Session-Cookie, das zwischen der Schicht [dao] und dem Datenserver ausgetauscht wird. Dieses wird durch die Funktion [getRemoteData] in den Zeilen 67–113 initialisiert;

Beim Sitzungs-Cookie müssen wir zwei getrennte Schichten [dao] berücksichtigen:

  • die des Browsers;
  • die des Servers;

Wir müssen drei Sitzungs-Cookies verwalten:

  1. das zwischen dem Client [nuxt] und dem Server PHP 7 ausgetauschte;
  2. das zwischen dem Server [nuxt] und dem Server PHP 7 ausgetauschte;
  3. das zwischen dem Client [nuxt] und dem Server [nuxt] ausgetauschte;

Wir sorgen dafür, dass das Sitzungs-Cookie mit dem Server PHP für den Client und den Server [nuxt] identisch ist. Wir bezeichnen dieses Cookie als Sitzungscookie PHP. Dieses Cookie entspricht den Fällen 1 und 2. Das Cookie aus Fall 3 bezeichnen wir als Sitzungscookie [nuxt]. Wir haben also zwei Sitzungen:

  • eine Sitzung PHP mit dem Sitzungs-Cookie PHP;
  • eine Sitzung [nuxt] mit dem Sitzungs-Cookie [nuxt];

Warum wird für die Sitzungen PHP des Clients und [nuxt] des Browsers dasselbe Cookie verwendet? Wir möchten, dass die Anwendung mit dem Server PHP kommunizieren kann, unabhängig davon, ob es sich um den Client oder den Server [nuxt] handelt:

  • Wenn eine Aktion A des Servers [nuxt] den Server PHP in einen Zustand E versetzt, spiegelt sich dieser Zustand in der vom Server PHP verwalteten Sitzung PHP wider;
  • unter Verwendung desselben Sitzungs-Cookies PHP wie der Server würde eine Aktion B des Clients [nuxt], die auf die Aktion A des Servers [nuxt] folgt, den Server PHP in demZustand E wiederfinden, der vom Server [nuxt] hinterlassen wurde, und könnte somit auf der bereits vom Server [nuxt] geleisteten Arbeit aufbauen;
  • wenn nach der Aktion B des Clients [nuxt] eine Aktion C des Servers [nuxt] folgt, kann diese Aktion aus demselben Grund wie zuvor auf der Arbeit aufbauen, die durch die Aktion B des Clients [nuxt] geleistet wurde;

Damit der Browser des Clients [nuxt] mit dem Steuerberechnungsserver PHP kommunizieren kann, verwenden wir die Version 14 dieses Servers, die domänenübergreifende Aufrufe zulässt, d. h. Aufrufe von einem Browser an den Server PHP. Aufrufe vom Server [nuxt] an den Server PHP sind hingegen keine domänenübergreifenden Aufrufe. Dieser Begriff gilt nur für Aufrufe, die von einem Browser aus erfolgen.

Kehren wir zum Code des Konstruktors der vorherigen Klasse [Dao] zurück:


// Konstruktor
  constructor(axios) {
    this.axios = axios;
    // Sitzungs-Cookie
    this.sessionCookieName = "PHPSESSID";
    this.sessionCookie = '';
}
  • Die Zeilen 5 und 6 beziehen sich auf das Sitzungs-Cookie PHP mit dem Server zur Steuerberechnung;

Die Verwaltung des oben genannten Sitzungs-Cookies PHP ist für den Server [nuxt] nicht geeignet: Seine Schicht [dao] wird bei jeder neuen Anfrage an den Server [nuxt] instanziiert. Man erinnere sich daran, dass das Anfordern einer Seite vom Server [nuxt] einem Neustart der Anwendung [nuxt] gleichkommt. Wenn also nach der ersten Anfrage des Servers [nuxt] an den Datenserver das Sitzungs-Cookie PHP der Schicht [dao] initialisiert wird, geht dieser Wert bei der folgenden Anfrage HTTP desselben Servers [nuxt] verloren, da in der Zwischenzeit seine Ebene [dao] neu erstellt, der Konstruktor erneut ausgeführt und das Sitzungs-Cookie PHP mit der leeren Zeichenkette zurückgesetzt wurde (Zeile 6);

Eine Lösung besteht darin, einen anderen Konstruktor für die Schicht [dao] des Servers zu verwenden:


// Konstruktor
  constructor(axios, phpSessionCookie) {
    // Axios-Bibliothek
    this.axios = axios
    // Wert des Sitzungs-Cookies
    this.phpSessionCookie = phpSessionCookie
    // Name des Server-Sitzungscookies PHP
    this.phpSessionCookieName = 'PHPSESSID'
  }
  • Zeile 2: Diesmal wird das Sitzungs-Cookie PHP an den Konstruktor der Schicht [dao] des Datenservers übergeben;

Wie kann der Server [nuxt] dieses Sitzungs-Cookie PHP an den Konstruktor seiner Schicht [dao] übergeben? Wir speichern das Sitzungs-Cookie PHP in dem Sitzungs-Cookie [nuxt], das zwischen dem Browser und dem Server [nuxt] ausgetauscht wird. Der Vorgang läuft wie folgt ab:

  1. Die Anwendung [nuxt] wird gestartet;
  2. wenn der Server [nuxt] seine erste Anfrage HTTP an den Server PHP sendet, speichert er das erhaltene Sitzungs-Cookie PHP in dem Sitzungs-Cookie [nuxt], das er mit dem Client [nuxt] austauscht;
  3. der Browser, auf dem der Client [nuxt] läuft, empfängt dieses Sitzungs-Cookie [nuxt] und sendet es daher bei jeder neuen Anfrage systematisch an den Server [nuxt] zurück;
  4. Wenn der Server [nuxt] eine neue Anfrage an den Server PHP stellen muss, findet er das Sitzungs-Cookie PHP in dem Sitzungs-Cookie [nuxt], das der Browser ihm gesendet hat. Er wird es dann an den Server PHP senden;

Es gibt tatsächlich zwei Sitzungscookies, die nicht verwechselt werden dürfen:

  • das Sitzungs-Cookie [nuxt], das zwischen dem Server [nuxt] und dem Browser des Kunden [nuxt] ausgetauscht wird;
  • das Sitzungs-Cookie PHP, das zwischen dem Server [nuxt] und dem Server PHP oder zwischen dem Client [nuxt] und dem Server PHP;

Kehren wir nun zum Code der Methode der Klasse [Dao] zurück. Sie enthält keine Funktion zum Beenden der Sitzung PHP mit dem Steuerberechnungsserver. Wir fügen diese hinzu:


// Ende der Steuersitzung
  async finSession() {
    // Anfrageoptionen HHTP  [get /main.php?action=fin-session]
    const options = {
      method: 'GET',
      // Parameter der Abfrage URL
      params: {
        action: 'fin-session'
      }
    }
    // Ausführung der Abfrage HTTP
    const data = await this.getRemoteData(options)
    // Ergebnis
    return data
  }

Bei Tests stellt sich heraus, dass die in Zeile 12 aufgerufene Funktion [getRemoteData] nicht für die Methode [finSession] geeignet ist:


async  getRemoteData(options) {
    // für das Sitzungs-Cookie
    if (!options.headers) {
      options.headers = {};
    }
    options.headers.Cookie = this.sessionCookie;
    // Ausführung der Anfrage HTTP
    let response;
    try {
      // asynchrone Anfrage
      response = await this.axios.request('main.php', options);
    } catch (error) {
      // Der Parameter [error] ist eine Ausnahmeinstanz – er kann verschiedene Formen annehmen
      if (error.response) {
        // Die Antwort des Servers befindet sich in [error.response]
        response = error.response;
      } else {
        // Der Fehler wird erneut ausgelöst
        throw error;
      }
    }
    // „response“ ist die gesamte Antwort HTTP des Servers (Header HTTP + die Antwort selbst)
    // Das Sitzungs-Cookie wird abgerufen, sofern es vorhanden ist
    const setCookie = response.headers['set-cookie'];
    if (setCookie) {
      // setCookie ist ein Array
      // Das Session-Cookie wird in diesem Array gesucht
      let trouvé = false;
      let i = 0;
      while (!trouvé && i < setCookie.length) {
        // Das Session-Cookie wird gesucht
        const results = RegExp('^(' + this.sessionCookieName + '.+?);').exec(setCookie[i]);
        if (results) {
          // Das Session-Cookie wird gespeichert
          // eslint-disable-next-line require-atomic-updates
          this.sessionCookie = results[1];
          // Es wurde gefunden
          trouvé = true;
        } else {
          // nächstes Element
          i++;
        }
      }
    }
    // Die Antwort des Servers lautet: [response.data]
    return response.data;
  }
  • Zeilen 30–43: Es wird nach dem Cookie [PHPSESSID=xxx] gesucht. Wird es gefunden, wird es in der Klasse gespeichert (Zeile 36);

Dieser Code ist für die neue Methode [finSession] nicht geeignet, da bei der Aktion [fin-session] der Server PHP zwei Cookies mit dem Namen [PHPSESSID] sendet. Hier ein Beispiel, das mit einem Client [Postman] ermittelt wurde:

Image

  • in [1], die Anfrage des Clients [Postman];
  • in [3], die Antwort des Servers PHP;
  • in [4] die Header HTTP der Serverantwort PHP;

Image

  • in [5] gibt der Server PHP zunächst an, dass er die aktuelle Sitzung PHP gelöscht hat;
  • Bei [6] sendet der Server PHP das Cookie der neuen Sitzung PHP;

Mit dem aktuellen Code ruft die Funktion [getRemoteData] das Cookie [5] ab, obwohl eigentlich das Cookie [6] gespeichert werden muss.

Daher muss der Code der Funktion [getRemoteData] angepasst werden:


async getRemoteData(options) {
    // Gibt es ein Session-Cookie mit dem Namen PHP?
    if (this.phpSessionCookie) {
      // Gibt es Header?
      if (!options.headers) {
        // Es wird ein leeres Objekt erstellt
        options.headers = {}
      }
      // Header des Session-Cookies PHP
      options.headers.Cookie = this.phpSessionCookie
    }
    // Ausführung der Anfrage HTTP
    let response
    try {
      // asynchrone Anfrage
      response = await this.axios.request('main.php', options)
    } catch (error) {
      // Der Parameter [error] ist eine Ausnahminstanz – er kann verschiedene Formen annehmen
      if (error.response) {
        // Die Antwort des Servers befindet sich in [error.response]
        response = error.response
      } else {
        // Der Fehler wird erneut ausgelöst
        throw error
      }
    }
    // „response“ ist die gesamte Antwort HTTP des Servers (Header HTTP + die Antwort selbst)
    // Das Sitzungs-Cookie PHP wird in den empfangenen Cookies gesucht
    // alle empfangenen Cookies
    const cookies = response.headers['set-cookie']
    if (cookies) {
      // Cookies sind ein Array
      // Es wird nach dem Sitzungs-Cookie „PHP“ in diesem Array gesucht
      let trouvé = false
      let i = 0
      while (!trouvé && i < cookies.length) {
        // Es wird nach dem Sitzungs-Cookie PHP gesucht
        const results = RegExp('^(' + this.phpSessionCookieName + '.+?)$').exec(cookies[i])
        if (results) {
          // Das Sitzungs-Cookie PHP wird gespeichert
          const phpSessionCookie = results[1]
          // Ist darin das Wort „[deleted]“ enthalten?
          const results2 = RegExp(this.phpSessionCookieName + '=deleted').exec(phpSessionCookie)
          if (!results2) {
            // Wir haben das richtige Sitzungs-Cookie PHP
            this.phpSessionCookie = phpSessionCookie
            // Es wurde gefunden
            trouvé = true
          } else {
            // nächstes Element
            i++
          }
        } else {
          // nächstes Element
          i++
        }
      }
    }
    // Die Antwort des Servers lautet [response.data]
    return response.data
  }
  • Zeile 41: Es wurde ein Cookie mit dem Namen [PHPSESSID] gefunden. Dieses wird lokal gespeichert;
  • Zeile 43: Es wird geprüft, ob in dem gespeicherten Cookie die Zeichenfolge [PHPSESSID=deleted] enthalten ist;
  • Zeile 46: Ist die Antwort „nein“, dann wurde das richtige Cookie „[PHPSESSID]“ gefunden. Es wird in der Klasse gespeichert;

Nach der Funktion [getRemoteData] wird das Sitzungs-Cookie PHP in der Klasse unter [this.phpSessionCookie] gespeichert. Es wurde gesagt, dass die Klasse bei jeder neuen Anfrage HTTP vom Server [nuxt] instanziiert wird. Das Session-Cookie PHP muss daher aus der Klasse extrahiert werden. Dazu fügen wir der Klasse eine neue Methode hinzu:


// Zugriff auf das Sitzungs-Cookie PHP
  getPhpSessionCookie() {
    return this.phpSessionCookie
}
  • Der Server [nuxt] fordert eine Aktion von seiner Schicht [dao] an, indem er dem Konstruktor dieses die Sitzungs-Cookie PHP übergibt, sofern dieser über einen solchen verfügt;
  • Sobald die Aktion ausgeführt wurde, ruft der Server [nuxt] das Sitzungs-Cookie PHP ab, das von der Schicht [dao] mithilfe der vorherigen Methode [getPhpSessionCookie] gespeichert wurde. Dieses Cookie kann dasselbe wie das vorherige sein oder ein anderes. Letzteres tritt in zwei Fällen auf:
    • bei der Ausführung der Methode [initSession] (zuvor gab es kein Sitzungs-Cookie PHP);
    • bei der Ausführung der Methode [finSession] (der Server PHP ändert das Sitzungs-Cookie PHP);

Es ist eine Besonderheit beim Session-Cookie PHP zu beachten. Der Server [nuxt] erhält dieses Cookie nicht immer vom Server PHP. Dieser sendet es nämlich nur einmal. Danach sendet er es nicht mehr. Betrachtet man den Code von [getRemoteData] und den von [getPhpSessionCookie], so wird deutlich, dass, wenn der Server PHP kein Sitzungs-Cookie sendet, gibt die Funktion [getPhpSessionCookie] das dem Konstruktor übergebene Sitzungs-Cookie PHP zurück. Auf diese Weise sendet der Server dem Server PHP stets das letzte Sitzungs-Cookie PHP, das dieser ihm gesendet hat.

15.5.2. Die Schicht [dao] des Clients [nuxt]

Image

Für den Client [nuxt], der in einem Browser ausgeführt wird, übernehmen wir den Code der Klasse [Dao] aus dem Dokument |Einführung in das Framework VUE.JS anhand eines Beispiels|:


"use strict";

// Importe
import qs from "qs";

class Dao {
  // Konstruktor
  constructor(axios) {
    this.axios = axios;
  }

  // Sitzung initialisieren
  async initSession() {
    // Anfrageoptionen HHTP [get /main.php?action=init-session&type=json]
    const options = {
      method: "GET",
      // Parameter der Abfrage URL
      params: {
        action: "init-session",
        type: "json"
      }
    };
    // Ausführung der Abfrage HTTP
    return await this.getRemoteData(options);
  }

  async authentifierUtilisateur(user, password) {
    // Optionen der Abfrage HHTP [post /main.php?action=authentifier-utilisateur]
    const options = {
      method: "POST",
      headers: {
        "Content-type": "application/x-www-form-urlencoded"
      },
      // Hauptteil von POST
      data: qs.stringify({
        user: user,
        password: password
      }),
      // Parameter des URL
      params: {
        action: "authentifier-utilisateur"
      }
    };
    // Ausführung der Abfrage HTTP
    return await this.getRemoteData(options);
  }

  async getAdminData() {
    // Optionen der Abfrage HHTP  [get /main.php?action=get-admindata]
    const options = {
      method: "GET",
      // Parameter der Abfrage URL
      params: {
        action: "get-admindata"
      }
    };
    // Ausführung der Abfrage HTTP
    const data = await this.getRemoteData(options);
    // Ergebnis
    return data;
  }

  async getRemoteData(options) {
    // Ausführung der Abfrage HTTP
    let response;
    try {
      // asynchrone Abfrage
      response = await this.axios.request("main.php", options);
    } catch (error) {
      // Der Parameter [error] ist eine Ausnahmeinstanz – er kann verschiedene Formen annehmen
      if (error.response) {
        // Die Antwort des Servers befindet sich in [error.response]
        response = error.response;
      } else {
        // Der Fehler wird erneut ausgelöst
        throw error;
      }
    }
    // „response“ ist die gesamte Antwort HTTP des Servers (Header HTTP + die Antwort selbst)
    // Die Antwort des Servers befindet sich in [response.data]
    return response.data;
  }
}

// Export der Klasse
export default Dao;

Dieser Code unterscheidet sich von der Schicht [dao] des Servers [nuxt] dadurch, dass er das Sitzungs-Cookie PHP nicht mit dem Steuerberechnungsserver verwaltet: Dies übernimmt der Browser.

Wir werden, wie bereits bei der Ebene [dao] des Servers [nuxt], eine Methode [finSession] hinzufügen:


// Ende der Steuerberechnungssitzung
  async finSession() {
    // Abfrageoptionen HHTP  [get /main.php?action=fin-session]
    const options = {
      method: 'GET',
      // Parameter der Abfrage URL
      params: {
        action: 'fin-session'
      }
    }
    // Ausführung der Abfrage HTTP
    const data = await this.getRemoteData(options)
    // Ergebnis
    return data
  }

Wenn der Client [nuxt] diese Methode ausführt, erhält er – genau wie der Server [nuxt] – zwei Sitzungs-Cookies PHP. Tatsächlich empfängt der Browser diese Cookies und geht korrekt damit um: Er behält nur das Cookie der neuen Sitzung PHP, die vom Steuerberechnungsserver initiiert wurde. Bei der nächsten Aktion des Clients [nuxt] gegenüber dem Server PHP ist das Sitzungs-Cookie PHP korrekt, da es vom Browser gesendet wird. Es gibt jedoch ein Problem: Der Server [nuxt] weiß nicht, dass sich das Sitzungs-Cookie PHP geändert hat. Bei seinem Datenaustausch mit dem Server PHP sendet er daher ein Sitzungs-Cookie PHP, das nicht mehr existiert, was zu Problemen führt. Der Client [nuxt] müsste den Server [nuxt] darüber informieren, dass sich das Sitzungs-Cookie PHP geändert hat, und ihm dieses übermitteln. Wir wissen, wie er das tun kann: über das Sitzungs-Cookie [nuxt], das zwischen dem Client und dem Server ausgetauschte Cookie [nuxt]. Der Client [nuxt] hat mindestens zwei Möglichkeiten, das neue Sitzungs-Cookie PHP abzurufen:

  1. indem er es vom Browser anfordert;
  2. durch Verwendung der Methode [getRemoteData] des Servers, der weiß, wie das neue Sitzungs-Cookie PHP abgerufen werden kann;

Wir werden die zweite Lösung verwenden, da sie bereits fertig ist. Die Methode [getRemoteData] des Clients [nuxt] sieht dann wie folgt aus:


async getRemoteData(options) {
    // Ausführung der Abfrage HTTP
    let response
    try {
      // asynchrone Abfrage
      response = await this.axios.request('main.php', options)
    } catch (error) {
      // Der Parameter [error] ist eine Ausnahmeinstanz – er kann verschiedene Formen annehmen
      if (error.response) {
        // Die Antwort des Servers befindet sich in [error.response]
        response = error.response
      } else {
        // Der Fehler wird erneut ausgelöst
        throw error
      }
    }
    // „response“ ist die gesamte Antwort HTTP des Servers (Header HTTP + die Antwort selbst)
    // Das Sitzungs-Cookie PHP wird in den empfangenen Cookies gesucht
    // alle empfangenen Cookies
    const cookies = response.headers['set-cookie']
    if (cookies) {
      // Cookies sind ein Array
      // Es wird nach dem Sitzungs-Cookie „PHP“ in diesem Array gesucht
      let trouvé = false
      let i = 0
      while (!trouvé && i < cookies.length) {
        // Es wird nach dem Sitzungs-Cookie PHP gesucht
        const results = RegExp('^(' + this.phpSessionCookieName + '.+?)$').exec(cookies[i])
        if (results) {
          // Das Sitzungs-Cookie PHP wird gespeichert
          const phpSessionCookie = results[1]
          // Ist darin das Wort „[deleted]“ enthalten?
          const results2 = RegExp(this.phpSessionCookieName + '=deleted').exec(phpSessionCookie)
          if (!results2) {
            // Wir haben das richtige Sitzungs-Cookie PHP
            this.phpSessionCookie = phpSessionCookie
            // Es wurde gefunden
            trouvé = true
          } else {
            // das nächste Element
            i++
          }
        } else {
          // nächstes Element
          i++
        }
      }
    }
    // Die Antwort des Servers lautet [response.data]
    return response.data
  }

In [getRemoteData] haben wir nur den Code beibehalten, der die Antwort des Servers PHP zur Suche nach dem Sitzungs-Cookie PHP auswertet. Der Code, der das Sitzungs-Cookie PHP in die Anfrage an den Server PHP einfügte, wurde nicht beibehalten, da dies vom Browser übernommen wird, in dem der Client [nuxt] läuft.

Sobald das Sitzungs-Cookie PHP vom Client [nuxt] abgerufen wurde, muss es in die Sitzung [nuxt] aufgenommen werden, damit der Server [nuxt] davon profitieren kann. Dies wird nicht von der Schicht [dao] übernommen, sondern sie gewährt über eine Methode Zugriff auf das von ihr gespeicherte Sitzungs-Cookie PHP:


// Zugriff auf das Sitzungs-Cookie PHP
  getPhpSessionCookie() {
    return this.phpSessionCookie
}

Die Funktion [getPhpSessionCookie] gibt nicht immer ein gültiges Sitzungs-Cookie zurück:

  • man muss hier bedenken, dass die Schicht [dao] des Clients [nuxt] persistent ist. Sie wird einmal instanziiert und verbleibt anschließend im Speicher;
  • solange der Server PHP kein Session-Cookie PHP an den Client [nuxt] sendet, gibt die Funktion [getPhpSessionCookie] des Clients [nuxt] den Wert [undefined] zurück;
  • wenn der Server PHP ein Sitzungs-Cookie PHP an den Client [nuxt] sendet, wird dieses in [this.phpSessionCookie] gespeichert und bleibt dort, bis es durch ein neues Sitzungs-Cookie PHP ersetzt wird, das vom Server PHP gesendet wird. Die Funktion [getPhpSessionCookie] des Clients [nuxt] gibt dann das zuletzt empfangene Sitzungs-Cookie PHP zurück;

Die Schicht [dao] des Clients [nuxt] unterscheidet sich von der des Servers [nuxt] nur in einem Punkt: Sie sendet das Sitzungs-Cookie PHP nicht selbst, da dies vom Browser übernommen wird. Dennoch wurde beschlossen, zwei getrennte Schichten [dao] beizubehalten, da die Überlegungen, die zu ihrer jeweiligen Implementierung führen, unterschiedlich sind.

15.6. Die Sitzung [nuxt]

Image

Die Sitzung [nuxt] (zwischen Client und Nuxt-Server) wird in das folgende Objekt [session] gekapselt:


/* eslint-disable no-console */
// Definition der Sitzung
const session = {
  // Inhalt der Sitzung
  value: {
    // Store nicht initialisiert
    initStoreDone: false,
    // Wert des Vuex-Stores
    store: ''
  },
  // Speicherung der Sitzung in einem Cookie
  save(context) {
    // Speicherung des Stores in der Sitzung
    this.value.store = context.store.state
    console.log('nuxt-session save=', this.value)
    // Speicherung des Sitzungswerts
    context.app.$cookies.set('nuxt-session', this.value, { path: context.base, maxAge: context.env.maxAge })
  },
  // Zurücksetzen der Sitzung
  reset(context) {
    console.log('nuxt-session reset')
    // Zurücksetzen des Speichers
    context.store.commit('reset')
    // Speichern des neuen Stores in der Sitzung und Speichern der Sitzung
    this.save(context)
  }
}
// Export der Sitzung
export default session
  • Zeilen 5–10: Die Sitzung hat nur eine Eigenschaft [value] mit zwei Untereigenschaften:
    • [initStoreDone], das angibt, ob der Store initialisiert wurde oder nicht;
    • [store]: der Wert [store.state] des Vuex-Stores der Anwendung;
  • Zeilen 12–18: Die Methode [save] dient dazu, die Sitzung [nuxt] in einem Cookie zu speichern. Hier wird die Bibliothek [cookie-universal-nuxt] zur Verwaltung des Cookies verwendet. Beachten Sie den Namen des Cookies der Sitzung [nuxt]: [nuxt-session] (Zeile 17);
  • Zeilen 20–26: Die Methode [reset] setzt die Sitzung [nuxt] zurück;
    • Zeile 23: Der Vuex-Store wird zurückgesetzt und anschließend in der Sitzung gespeichert (Zeile 25);

15.7. Die Plugins zur Sitzungsverwaltung [nuxt]

Image

15.7.1. Das Plugin zur Sitzungsverwaltung [nuxt] des serveur [nuxt]

Beim Start der Anwendung wird zunächst der Server [nuxt] ausgeführt. Dieser initialisiert daher die Sitzung [nuxt]. Das Skript [server/plgSession] lautet wie folgt:


/* eslint-disable no-console */

// Import der Sitzung
import session from '@/entities/session'

export default (context, inject) => {
  // Verwaltung der Serversitzung
  console.log('[plugin server plgSession]')

  // Gibt es bereits eine Sitzung?
  const value = context.app.$cookies.get('nuxt-session')
  if (!value) {
    // Neue Sitzung
    console.log("[plugin server plgSession], démarrage d'une nouvelle session")
  } else {
    // bestehende Sitzung
    console.log("[plugin server plgSession], reprise d'une session existante")
    session.value = value
  }

  // Es wird eine Funktion in [context, Vue] eingefügt, die die aktuelle Sitzung aktiviert
  inject('session', () => session)
}
  • Zeile 4: Der Code der Sitzung [nuxt] wird importiert;
  • Zeile 11: Der Wert des Cookies der Sitzung [nuxt] wird abgerufen;
  • Zeilen 12–15: Wenn das Sitzungs-Cookie [nuxt] nicht existierte, reicht die in Zeile 4 importierte Sitzung [nuxt] aus. Es ist nichts weiter zu tun;
  • Zeilen 15–19: Wenn das Sitzungs-Cookie [nuxt] vorhanden wäre, wird in Zeile 18 dessen Wert in der in Zeile 4 importierten Sitzung gespeichert;
  • Zeile 22: Die Sitzung wurde entweder initialisiert oder wiederhergestellt. Sie wird über die Funktion [$session] zur Verfügung gestellt;

15.7.2. Das Sitzungsverwaltungs-Plugin [nuxt] des Clients [nuxt]

Das Skript [client/plgSession] lautet wie folgt:


/* eslint-disable no-console */

// Import der Sitzung
import session from '@/entities/session'

export default (context, inject) => {
  // Verwaltung der Client-Sitzung
  console.log('[plugin client plgSession], reprise de la session [nuxt] du serveur')
  // Die bestehende Sitzung wird vom Nuxt-Server abgerufen
  session.value = context.app.$cookies.get('nuxt-session')

  // Wir fügen eine Funktion in [context, Vue] ein, die die aktuelle Sitzung aktiviert
  inject('session', () => session)
}
  • Zeile 4: Die Sitzung [nuxt] wird importiert;
  • Zeile 10: Die aktuelle Sitzung [nuxt] wird aus dem Cookie [nuxt-session] abgerufen;
  • Zeile 13: Die in Zeile 4 importierte Sitzung [nuxt] wird über die eingeschleuste Funktion [$session] zurückgegeben;

15.8. Die Plugins der Ebenen [dao]

Image

15.8.1. Das Plugin der Ebene [dao] des Clients [nuxt]

Das Skript [client/plgDao] lautet wie folgt:


/* eslint-disable no-console */
// Es wird ein Zugriffspunkt auf die Ebene [Dao] erstellt
import Dao from '@/api/client/Dao'
export default (context, inject) => {
  // Konfiguration von Axios
  context.$axios.defaults.timeout = context.env.timeout
  context.$axios.defaults.baseURL = context.env.baseURL
  context.$axios.defaults.withCredentials = context.env.withCredentials
  // Instanziierung der Schicht [dao]
  const dao = new Dao(context.$axios)
  // Einfügen einer Funktion [$dao] in den Kontext
  inject('dao', () => dao)
  // Protokoll
  console.log('[fonction client $dao créée]')
}
  • Zeile 3: Die Ebene [dao] des Clients [nuxt] wird importiert;
  • Zeilen 6–8: Es wird dasObjekt [context.$axios], das die Abfragen HTTP der Schicht [dao] des Clients [nuxt] mit den Informationen aus der Datei [nuxt.config] ausführt:

// Umgebung
  env: {
    // Axios-Konfiguration
    timeout: 2000,
    withCredentials: true,
    baseURL: 'http://localhost/php7/scripts-web/impots/version-14',
    // Konfiguration des Sitzungs-Cookies [nuxt]
    maxAge: 60 * 5
  }
  • Zeile 10: Die Schicht [dao] des Clients [nuxt] wird instanziiert;
  • Zeile 12: Die Funktion [$dao] wird in den Kontext und die Seiten des Clients eingefügt. Diese Funktion ermöglicht den Zugriff auf die Schicht [dao] aus Zeile 10;

Man beachte also, dass man, um bei der Ausführung des Clients [nuxt] Zugriff auf die Schicht [dao] zu erhalten, Folgendes schreibt:

  • [context.app.$dao()], wenn der Kontext bekannt ist;
  • [this.$dao()] auf einer Seite [Vue.js];

15.8.2. Das Plugin der Ebene [dao] von serveur [nuxt]

Das Skript [server/plgDao] lautet wie folgt:


/* eslint-disable no-console */
// Es wird ein Zugriffspunkt auf die Schicht [Dao] erstellt
import Dao from '@/api/server/Dao'
export default (context, inject) => {
  // Konfiguration von Axios
  context.$axios.defaults.timeout = context.env.timeout
  context.$axios.defaults.baseURL = context.env.baseURL
  // Das Sitzungs-Cookie wird abgerufen
  const store = context.app.$session().value.store
  const phpSessionCookie = store ? store.phpSessionCookie : ''
  console.log('session=', context.app.$session().value, 'phpSessionCookie=', phpSessionCookie)
  // Instanziierung der Schicht [dao]
  const dao = new Dao(context.$axios, phpSessionCookie)
  // Einfügen einer Funktion [$dao] in den Kontext
  inject('dao', () => dao)
  // Protokollierung
  console.log('[fonction server $dao créée]')
}
  • Zeile 3: Die Ebene [dao] des Servers [nuxt] wird importiert;
  • Zeilen 6–7: Es wird dasObjekt [context.$axios], das die Abfragen HTTP der Ebene [dao] des Servers [nuxt] mit den Informationen aus der Datei [nuxt.config] ausführt:

// Umgebung
  env: {
    // Axios-Konfiguration
    timeout: 2000,
    withCredentials: true,
    baseURL: 'http://localhost/php7/scripts-web/impots/version-14',
    // Konfiguration des Sitzungs-Cookies [nuxt]
    maxAge: 60 * 5
  }
  • Zeile 9: Der Speicher der Anwendung [nuxt] wird abgerufen;
  • Zeile 10: Wenn der Store vorhanden ist, wird das Sitzungs-Cookie von PHP abgerufen, da es zum Instanziieren der Schicht [dao] des Servers [nuxt] benötigt wird;
  • Zeile 13: Die Schicht [dao] des Servers [nuxt] wird instanziiert;
  • Zeile 15: Die Funktion [$dao] wird in den Kontext und die Seiten des Servers [nuxt] eingefügt. Diese Funktion ermöglicht den Zugriff auf die Schicht [dao] aus Zeile 13;

Man beachte also, dass man, um Zugriff auf die Ebene [dao] des Servers [nuxt] zu erhalten, wenn dieser ausgeführt wird, Folgendes schreibt:

  • [context.app.$dao()], wenn der Kontext bekannt ist;
  • [this.$dao()] auf einer Seite [Vue.js];

15.9. Der Vuex-Store

Image

Der Speicher [Vuex] speichert alle Daten, die von den verschiedenen Komponenten der Anwendung [pages, client, serveur] gemeinsam genutzt werden sollen, ohne dass diese Daten reaktiv sind.


/* eslint-disable no-console */

// Status der Jalousie
export const state = () => ({
  // Sitzung jSON gestartet
  jsonSessionStarted: false,
  // Benutzer authentifiziert
  userAuthenticated: false,
  // Sitzungs-Cookie PHP
  phpSessionCookie: '',
  // adminData
  adminData: ''
})

// Änderungen im Store
export const mutations = {
  // Ersetzen des Status
  replace(state, newState) {
    for (const attr in newState) {
      state[attr] = newState[attr]
    }
  },
  // Speicher zurücksetzen
  reset() {
    this.commit('replace', { jsonSessionStarted: false, userAuthenticated: false, phpSessionCookie: '', adminData: '' })
  }
}

// Aktionen des Speichers
export const actions = {
  nuxtServerInit(store, context) {
    // Wer führt diesen Code aus?
    console.log('nuxtServerInit, client=', process.client, 'serveur=', process.server, 'env=', context.env)
    // Sitzung initialisieren
    initStore(store, context)
  }
}

function initStore(store, context) {
  // store ist die zu initialisierende Sitzung
  // die Sitzung wird abgerufen
  const session = context.app.$session()
  // Wurde die Sitzung bereits initialisiert?
  if (!session.value.initStoreDone) {
    // Ein neuer Store wird gestartet
    console.log("nuxtServerInit, initialisation d'une nouvelle session")
    // Der Store wird in die Sitzung aufgenommen
    session.value.store = store.state
    // Der Speicher ist nun initialisiert
    session.value.initStoreDone = true
  } else {
    console.log("nuxtServerInit, reprise d'un store existant")
    // Der Speicher wird mit dem Speicher der Sitzung aktualisiert
    store.commit('replace', session.value.store)
  }
  // Die Sitzung wird gespeichert
  session.save(context)
  // Protokoll
  console.log('initStore terminé, store=', store.state)
}

Die im Speicher gespeicherten Daten sind folgende:

  • Zeile 6: [jsonSessionStarted] wird auf „wahr“ gesetzt, sobald die Initialisierung einer Sitzung jSON mit dem Server PHP erfolgreich abgeschlossen wurde, unabhängig davon, ob diese durch den Client oder den Server [nuxt] erfolgt ist. Nach Abschluss dieser Initialisierung wird das Sitzungs-Cookie des Servers PHP abgerufen und in die Eigenschaft [phpSessionCookie] in Zeile 10 geschrieben;
  • Zeile 8: [userAuthenticated] wird auf „wahr“ gesetzt, sobald die Authentifizierung beim Server PHP erfolgreich war, unabhängig davon, ob sie vom Client oder vom Server [nuxt] durchgeführt wurde;
  • Zeile 12: [adminData] ist der Wert [adminData], der nach erfolgreicher Authentifizierung vom Server PHP abgerufen wurde;
  • Zeilen 18–22: Die Mutation [replace] ermöglicht es, die vorherigen Eigenschaften mit denen eines als Parameter übergebenen Objekts zu initialisieren;
  • Zeilen 24–26: Die Mutation [reset] setzt die Eigenschaften des Stores wieder auf ihre ursprünglichen Werte zurück;
  • Zeilen 31–37: Die Funktion [nuxtServerInit] delegiert ihre Aufgabe an die Funktion [initStore];
  • Zeilen 39–60: Die Funktion [initStore] hat zwei Aufgaben:
    • Wenn der Speicher noch nicht initialisiert wurde, wird er initialisiert und in die Sitzung aufgenommen;
    • wenn der Store bereits initialisiert wurde, wird sein Wert aus der Sitzung [nuxt] abgerufen;
  • Zeile 42: Die Nuxt-Sitzung wird abgerufen;
  • Zeile 44: Es wird geprüft, ob der Store initialisiert wurde:
    • Ist dies nicht der Fall, wird der ursprüngliche Store in die Sitzung geschrieben (Zeile 48);
    • anschließend wird in Zeile 50 angegeben, dass der Store initialisiert wurde;
  • Zeilen 51–55: Wenn der Store initialisiert wurde, wird dieser in Zeile 54 verwendet, um den Store mit dem in der Sitzung enthaltenen Wert zu initialisieren;
  • Zeile 57: In jedem Fall wird die Sitzung zusammen mit dem darin enthaltenen Speicher im Cookie „[nuxt-session]“ gespeichert;

15.10. Das Plugin [plgEventBus]

Image

Dieses Plugin zielt darauf ab, dem Client [nuxt] über eine Funktion [$eventBus], die in den Kontext des Clients [nuxt] eingefügt wird, einen Ereignisbus zugänglich zu machen. Es ist sinnlos, es in den Kontext des Servers [nuxt] einzuschleusen, da dieser keine Ereignisse verarbeiten kann. Dennoch haben wir bereits gesehen, dass das serverseitige Einschleusen und anschließende Verwenden keine Fehler verursacht.


/* eslint-disable no-console */
// Es wird ein Ereignisbus zwischen den Ansichten erstellt
import Vue from 'vue'
export default (context, inject) => {
  // der Ereignisbus
  const eventBus = new Vue()
  // Einfügen einer Funktion [$eventBus] in den Kontext
  inject('eventBus', () => eventBus)
  // Protokollierung
  console.log('[fonction $eventBus créée]')
}

Dieses Plugin haben wir bereits im Abschnitt „Link“ kennengelernt. Die Funktion [$eventBus] steht dem Client über die folgenden Bezeichnungen zur Verfügung:

  • [context.app.$eventBus()], sofern der Kontext verfügbar ist;
  • [this.$eventBus()] auf den Seiten [Vue.js] des Clients;

15.11. Die Komponenten der Anwendung [nuxt]

Image

Die Komponente [layout] ist die aus den vorherigen Beispielen:


<!-- Anordnung der Ansichten -->
<template>
  <!-- Zeile -->
  <div>
    <b-row>
      <!-- Feld mit drei Spalten -->
      <b-col v-if="left" cols="3">
        <slot name="left" />
      </b-col>
      <!-- neunsäuliger Bereich -->
      <b-col v-if="right" cols="9">
        <slot name="right" />
      </b-col>
    </b-row>
  </div>
</template>

<script>
export default {
  // Einstellungen
  props: {
    left: {
      type: Boolean
    },
    right: {
      type: Boolean
    }
  }
}
</script>

Die Komponente [navigation] lautet wie folgt:


<template>
  <!-- Bootstrap-Menü mit drei Optionen -->
  <b-nav vertical>
    <b-nav-item to="/authentification" exact exact-active-class="active">
      Authentification
    </b-nav-item>
    <b-nav-item to="/get-admindata" exact exact-active-class="active">
      Requête AdminData
    </b-nav-item>
    <b-nav-item to="/fin-session" exact exact-active-class="active">
      Fin session impôt
    </b-nav-item>
  </b-nav>
</template>

15.12. Die Layouts der Anwendung [nuxt]

Image

15.12.1. [default]

Das Layout [default] wird für das Beispiel [nuxt-11] im Abschnitt „Link“ verwendet:


<template>
  <div class="container">
    <b-card>
      <!-- eine Meldung -->
      <b-alert show variant="success" align="center">
        <h4>[nuxt-12] : requêtes HTTP avec axios</h4>
      </b-alert>
      <!-- die aktuelle Ansicht der Routenführung -->
      <nuxt />
      <!-- Wartemeldung -->
      <b-alert v-if="showLoading" show variant="light">
        <strong>Requête au serveur de données en cours...</strong>
        <div class="spinner-border ml-auto" role="status" aria-hidden="true"></div>
      </b-alert>
      <!-- Fehler bei einem asynchronen Vorgang -->
      <b-alert v-if="showErrorLoading" show variant="danger">
        <strong>La requête au serveur de données a échoué : {{ errorLoadingMessage }}</strong>
      </b-alert>
    </b-card>
  </div>
</template>

<script>
/* eslint-disable no-console */
export default {
  name: 'App',
  data() {
    return {
      showLoading: false,
      showErrorLoading: false
    }
  },
  // Lebenszyklus
  beforeCreate() {
    console.log('[default beforeCreate]')
  },
  created() {
    console.log('[default created]')
    if (process.client) {
      // Das Ereignis [loading] wird abgehört
      this.$eventBus().$on('loading', this.mShowLoading)
      // sowie das Ereignis [errorLoadingMessage]
      this.$eventBus().$on('errorLoading', this.mShowErrorLoading)
    }
  },
  beforeMount() {
    console.log('[default beforeMount]')
  },
  mounted() {
    console.log('[default mounted]')
  },
  methods: {
    // Verwaltung der Wartemeldung
    mShowLoading(value) {
      console.log('[default mShowLoading], showLoading=', value)
      this.showLoading = value
    },
    // Fehler bei einem asynchronen Vorgang
    mShowErrorLoading(value, errorLoadingMessage) {
      console.log('[default mShowErrorLoading], showErrorLoading=', value, 'errorLoadingMessage=', errorLoadingMessage)
      this.showErrorLoading = value
      this.errorLoadingMessage = errorLoadingMessage
    }
  }
}
</script>
  • Zeilen 10–14: Zeigen die Meldung an, dass auf das Ende eines asynchronen Vorgangs des Clients [nuxt] gewartet wird;
  • Zeilen 15–18: Zeigen die eventuelle Fehlermeldung einer asynchronen Operation an;
  • Zeile 37: Die Funktion [created] der Seite [default] wird vor der Funktion [mounted] der Seiten ausgeführt;
  • Zeile 39: Wenn der Ausführer der Client [nuxt] ist, dann wartet die Seite [default] auf die Ereignisse:
    • [loading], die den Beginn oder das Ende einer Wartezeit signalisiert. Daraufhin wird die Funktion [mShowLoading] ausgeführt;
    • [errorLoading], das signalisiert, dass eine Fehlermeldung angezeigt werden muss. Die Funktion [mShowErrorLoading] wird dann ausgeführt;
  • die Seiten [nuxt]:
    • lassen die Warteanzeige erscheinen, indem sie das Ereignis [‘loading’, true] auf den Ereignisbus senden;
    • blenden die Wartemeldung aus, indem sie das Ereignis [‘loading’, false] auf den Ereignisbus senden;
    • zeigen eine Fehlermeldung an, indem sie das Ereignis [‘errorLoading’, true] auf den Ereignisbus senden;
    • blenden die Fehlermeldung aus, indem sie das Ereignis [‘errorLoading’, false] auf den Ereignisbus senden;

15.12.2. [error]

Das Layout [error] zeigt eine Systemfehlermeldung an (die nicht vom Entwickler verwaltet wird):


<!-- Definition der Ansicht HTML -->
<template>
  <!-- Layout -->
  <Layout :left="true" :right="true">
    <!-- Warnung in der rechten Spalte -->
    <template slot="right">
      <!-- Meldung auf rosa Hintergrund -->
      <b-alert show variant="danger" align="center">
        <h4>L'erreur suivante s'est produite : {{ JSON.stringify(error) }}</h4>
      </b-alert>
    </template>
    <!-- Navigationsmenü in der linken Spalte -->
    <Navigation slot="left" />
  </Layout>
</template>

<script>
/* eslint-disable no-undef */
/* eslint-disable no-console */
/* eslint-disable nuxt/no-env-in-hooks */

import Layout from '@/components/layout'
import Navigation from '@/components/navigation'

export default {
  name: 'Error',
  // verwendete Komponenten
  components: {
    Layout,
    Navigation
  },
  // Eigenschaft [props]
  props: { error: { type: Object, default: () => 'waiting ...' } },
  // Lebenszyklus
  beforeCreate() {
    // Client und Server
    console.log('[error beforeCreate]')
  },
  created() {
    // Client und Server
    console.log('[error created, error=]', this.error)
  },
  beforeMount() {
    // nur Client
    console.log('[error beforeMount]')
  },
  mounted() {
    // nur Client
    console.log('[error mounted]')
  }
}
</script>

15.13. Die Seite [index], die vom Server [nuxt] ausgeführt wird

Image

Die Seite [index.vue] zeichnet sich dadurch aus, dass sie ausschließlich über den Server [nuxt] erreichbar ist. Dem Benutzer wird kein Link angezeigt, über den er über den Client [nuxt] darauf zugreifen könnte. Ihr Code lautet wie folgt:


<!-- Startseite -->
<template>
  <Layout :left="true" :right="true">
    <!-- Navigation -->
    <Navigation slot="left" />
    <!-- Meldung-->
    <b-alert slot="right" show variant="warning">Initialisation de la session avec le serveur de calcul de l'impôt : {{ result }} </b-alert>
  </Layout>
</template>

<script>
/* eslint-disable no-console */

import Navigation from '@/components/navigation'
import Layout from '@/components/layout'

export default {
  name: 'InitSession',
  // verwendete Komponenten
  components: {
    Layout,
    Navigation
  },
  // asynchrone Daten
  async asyncData(context) {
    // Protokoll
    console.log('[index asyncData started]')
    try {
      // Eine Sitzung wird gestartet jSON
      const dao = context.app.$dao()
      const response = await dao.initSession()
      // Protokoll
      console.log('[index asyncData response=]', response)
      // Das Sitzungs-Cookie PHP wird für die nächsten Anfragen abgerufen
      const phpSessionCookie = dao.getPhpSessionCookie()
      // Das Sitzungs-Cookie PHP wird in der Sitzung [nuxt] gespeichert
      context.store.commit('replace', { phpSessionCookie })
      // Ist ein Fehler aufgetreten?
      if (response.état !== 700) {
        // Der Fehler befindet sich in response.réponse
        throw new Error(response.réponse)
      }
      // Es ist zu beachten, dass die Sitzung jSON gestartet wurde
      context.store.commit('replace', { jsonSessionStarted: true })
      // Das Ergebnis wird ausgegeben
      return { result: '[succès]' }
    } catch (e) {
      // Protokoll
      console.log('[index asyncData error=]', e)
      // Es wird vermerkt, dass die Sitzung jSON nicht gestartet wurde
      context.store.commit('replace', { jsonSessionStarted: false })
      // Der Fehler wird gemeldet
      return { result: '[échec]', showErrorLoading: true, errorLoadingMessage: e.message }
    } finally {
      // Der Speicher wird gesichert
      const session = context.app.$session()
      session.save(context)
      // Protokoll
      console.log('[index asyncData finished]')
    }
  },
  // Lebenszyklus
  beforeCreate() {
    console.log('[index beforeCreate]')
  },
  created() {
    console.log('[index created]')
  },
  beforeMount() {
    console.log('[index beforeMount]')
  },
  mounted() {
    console.log('[index mounted]')
    // nur Client
    if (this.showErrorLoading) {
      console.log('[index mounted, showErrorLoading=true]')
      this.$eventBus().$emit('errorLoading', true, this.errorLoadingMessage)
    }
  }
}
</script>
  • Zeile 7: Die Seite zeigt das Ergebnis [result] einer asynchronen Abfrage an (Zeilen 46 und 51);
  • Zeile 31: Der asynchrone Vorgang ist das Öffnen einer Sitzung jSON mit dem Steuerberechnungsserver;
  • Zeile 25: Es ist bekannt, dass, wenn die Seite direkt beim Server [nuxt] angefordert wird, die Funktion [asyncData] nur vom Server und nicht vom Client [nuxt] ausgeführt wird, der dann läuft, wenn der Browser die Antwort vom Server [nuxt] erhalten hat;
  • Zeile 30: Die Schicht [dao] wird im Kontext des Servers [nuxt] abgerufen;
  • Zeile 35: Falls der Server noch keine Anfrage an den Steuerberechnungsserver gestellt hat, erhält er sein erstes Sitzungs-Cookie PHP, andernfalls das letzte Sitzungs-Cookie PHP, das er erhalten hat (siehe den Code der Schicht [dao] des Servers [nuxt] im Abschnitt „Link“);
  • Zeile 37: Dieses Session-Cookie „PHP“ wird im Speicher abgelegt;
  • Zeilen 39–42: Es wird geprüft, ob der Vorgang erfolgreich war. Ist dies nicht der Fall, wird eine Ausnahme ausgelöst, die von [catch] in Zeile 47 abgefangen wird;
  • Zeile 44: Im Speicher wird vermerkt, dass die Sitzung jSON mit dem Server PHP gestartet wurde;
  • Zeile 46: Das Ergebnis [result] wird zurückgegeben und in Zeile 7 angezeigt;
  • Zeilen 47–54: Eine eventuelle Ausnahme wird behandelt. Diese kann zweierlei Art sein:
    • Der Vorgang HTTP in Zeile 31 ist aufgrund eines Kommunikationsfehlers zwischen dem Server [nuxt] und dem Server PHP fehlgeschlagen;
    • der Vorgang HTTP in Zeile 31 war erfolgreich, aber das empfangene Ergebnis wies auf einen Fehler hin (Zeilen 39–42);
  • Zeile 51: Es ist festzustellen, dass die Sitzung jSON mit dem Server PHP nicht gestartet wurde;
  • Zeile 53: Das Ergebnis [result] wird zurückgegeben und in Zeile 7 angezeigt. Außerdem werden die Eigenschaften [showErrorLoading] und [errorLoadingMessage] festgelegt, die der Client [nuxt] verwenden wird, um eine Fehlermeldung anzuzeigen, wenn er die vom Server [nuxt] gesendete Seite empfängt (Zeilen 72–79);
  • Zeilen 54–60: Code, der in jedem Fall ausgeführt wird (erfolgreich oder fehlgeschlagen);
  • Zeile 56: Die Sitzung [nuxt] wird im Kontext des Servers [nuxt] abgerufen;
  • Zeile 57: Diese wird gespeichert;
  • Zeilen 63–68: Sobald die Funktion [asyncData] beendet ist, führt der Server [nuxt] die Funktionen [beforeCreate] und [create] aus;

Hinweis: Die Ausführung der Seite [index] durch den Server [nuxt] kann beispielsweise fehlschlagen, wenn der Steuerberechnungsserver nicht gestartet ist, wenn die Anwendung [nuxt] gestartet wird:

Image

In diesem Fall besteht die einzige Lösung darin, zunächst den Steuerberechnungsserver und anschließend die Anwendung [nuxt] selbst zu starten, da das Navigationsmenü keine Option zum Starten einer Sitzung jSON mit dem Steuerberechnungsserver bietet;

15.14. Die Seite [index], die vom Client [nuxt] ausgeführt wird

Die Seite [index] wird vom Client [nuxt] erst ausgeführt, nachdem der Server [nuxt] sie an ihn gesendet hat. Dieser hat ihm die Informationen [result] und gegebenenfalls [showErrorLoading] sowie [errorLoadingMessage] gesendet.

Es ist bekannt, dass die Funktion [asyncData] nicht ausgeführt wird. Es bleiben also die Funktionen des Lebenszyklus und insbesondere die Funktion [mounted]:


mounted() {
    console.log('[index mounted]')
    // nur Client
    if (this.showErrorLoading) {
      console.log('[index mounted, showErrorLoading=true]')
      this.$eventBus().$emit('errorLoading', true, this.errorLoadingMessage)
    }
}
  • Der Client [nuxt] fügt automatisch die Elemente [result] und gegebenenfalls [showErrorLoading, errorLoadingMessage], die ihm der Server [nuxt] gesendet hat, in die Eigenschaften der Seite ein:
  • Die Eigenschaft [result] wird in Zeile 7 angezeigt;
  • die Eigenschaften [showErrorLoading, errorLoadingMessage] werden von der Methode [mounted] verwendet: In Zeile 4 wird die Eigenschaft [showErrorLoading] geprüft. Ist sie wahr, wird in Zeile 6 der Ereignisbus des Clients [nuxt] verwendet, um zu signalisieren, dass eine Fehlermeldung angezeigt werden muss;
  • das in Zeile 6 ausgelöste Ereignis [errorLoading] wird von der im Abschnitt „Link“ beschriebenen Seite [layouts/default] abgefangen;

15.15. Die Seite [authentification] wird vom Server [nuxt] ausgeführt

Die Seite [authentification] ist dafür zuständig, einen Benutzer beim Steuerberechnungsserver zu identifizieren. Ihr Code lautet wie folgt:


<!-- Anmeldeseite -->
<template>
  <Layout :left="true" :right="true">
    <!-- Navigation -->
    <Navigation slot="left" />
    <!-- Meldung-->
    <b-alert slot="right" show variant="warning">Authentification auprès du serveur de calcul de l'impôt : {{ result }} </b-alert>
  </Layout>
</template>

<script>
/* eslint-disable no-console */

import Navigation from '@/components/navigation'
import Layout from '@/components/layout'

export default {
  name: 'Authentification',
  // verwendete Komponenten
  components: {
    Layout,
    Navigation
  },
  // asynchrone Daten
  async asyncData(context) {
    // Protokoll
    console.log('[authentification asyncData started]')
    if (process.client) {
      // Beginn der Wartezeit auf den Client [nuxt]
      context.app.$eventBus().$emit('loading', true)
      // kein Fehler
      context.app.$eventBus().$emit('errorLoading', false)
    }
    try {
      // Authentifizierung beim Server
      const dao = context.app.$dao()
      const response = await dao.authentifierUtilisateur('admin', 'admin')
      // Protokoll
      console.log('[authentification asyncData response=]', response)
      // Ergebnis
      const userAuthenticated = response.état === 200
      // Es wird vermerkt, ob der Benutzer authentifiziert ist oder nicht
      context.store.commit('replace', { userAuthenticated })
      // Der Speicher wird in der Sitzung gespeichert [nuxt]
      const session = context.app.$session()
      session.save(context)
      // Authentifizierungsfehler?
      if (!userAuthenticated) {
        // Der Fehler befindet sich in response.réponse
        throw new Error(response.réponse)
      }
      // ergibt das Ergebnis
      return { result: '[succès]' }
    } catch (e) {
      // der Fehler wird gemeldet
      return { result: '[échec]', showErrorLoading: true, errorLoadingMessage: e.message }
    } finally {
      // Protokoll
      console.log('[authentification asyncData finished]')
      if (process.client) {
        // Ende der Wartezeit auf den Client [nuxt]
        context.app.$eventBus().$emit('loading', false)
      }
    }
  },
  // Lebenszyklus
  beforeCreate() {
    console.log('[authentification beforeCreate]')
  },
  created() {
    console.log('[authentification created]')
  },
  beforeMount() {
    console.log('[authentification beforeMount]')
  },
  mounted() {
    console.log('[authentification mounted]')
    // nur Kunde
    if (this.showErrorLoading) {
      console.log('[authentification mounted, showErrorLoading=true]')
      this.$eventBus().$emit('errorLoading', true, this.errorLoadingMessage)
    }
  }
}
</script>
  • Zeile 7: Die Seite zeigt das Ergebnis [result] der asynchronen Abfrage [asyncData] aus den Zeilen 25–65 an;
  • Zeilen 28–33: Der Server führt diese für den Client bestimmten Zeilen [nuxt] nicht aus;
  • Zeile 36: Die Ebene [dao] wird vom Server [nuxt] abgerufen;
  • Zeile 37: Man authentifiziert sich beim Steuerberechnungsserver mit den Test-Anmeldedaten [admin, admin], die als einzige vom Steuerberechnungsserver akzeptiert werden;
  • Zeile 41: Die Authentifizierung war erfolgreich, sofern die Antwort den Status 200 aufweist;
  • Zeile 43: Die Eigenschaft [userAuthenticated] wird im Speicher abgelegt;
  • Zeilen 44–46: Der Store wird in der Sitzung [nuxt] gespeichert;
  • Zeilen 48–51: Wenn die Authentifizierung fehlgeschlagen ist, wird eine Ausnahme mit der vom Steuerberechnungsserver gesendeten Fehlermeldung ausgelöst;
  • ansonsten (Zeile 53) wird ein Erfolgsergebnis zurückgegeben, das in Zeile 7 angezeigt wird;
  • Zeilen 54–57: Im Fehlerfall werden drei Eigenschaften der Seite [result, showErrorLoading, errorLoadingMessage] gesetzt. Die Eigenschaft [result] wird in Zeile 7 angezeigt. Die drei Eigenschaften werden an den Client [nuxt] gesendet;
  • Zeilen 60–63: werden vom Server [nuxt] nicht ausgeführt;
  • Sobald [asyncData] sein Ergebnis zurückgegeben hat, wird dieses in Zeile 7 angezeigt. Anschließend werden die Methoden [beforeCreate] (Zeilen 67–69) und [created] (Zeilen 70–72) ausgeführt;
  • Das war’s;

Hinweis: Die Ausführung der Seite [authentification] durch den Server [nuxt] kann beispielsweise fehlschlagen, wenn die Sitzung jSON mit dem Steuerberechnungsserver nicht initialisiert wurde. Dies lässt sich wie folgt beheben:

  • Löschen Sie das Sitzungs-Cookie PHP aus Ihrem Browser (um von vorne zu beginnen):

Image

  • Starten Sie die Anwendung [nuxt], während der Berechnungsserver noch nicht gestartet wurde: Sie erhalten eine Fehlermeldung;
  • Starten Sie den Steuerberechnungsserver;
  • Rufen Sie die URL [/authentification] direkt in der Adressleiste des Browsers auf:

Image

In diesem Fall besteht die einzige Lösung erneut darin, die Seite [index] neu zu laden.

15.16. Die vom Client ausgeführte Seite [authentification]

Schauen wir uns den Code der Seite noch einmal an:


<!-- Authentifizierungsseite -->
<template>
  <Layout :left="true" :right="true">
    <!-- Navigation -->
    <Navigation slot="left" />
    <!-- Meldung-->
    <b-alert slot="right" show variant="warning">Authentification auprès du serveur de calcul de l'impôt : {{ result }} </b-alert>
  </Layout>
</template>

<script>
/* eslint-disable no-console */

import Navigation from '@/components/navigation'
import Layout from '@/components/layout'

export default {
  name: 'Authentification',
  // verwendete Komponenten
  components: {
    Layout,
    Navigation
  },
  // asynchrone Daten
  async asyncData(context) {
    // Protokoll
    console.log('[authentification asyncData started]')
    if (process.client) {
      // Beginn der Wartezeit auf den Client [nuxt]
      context.app.$eventBus().$emit('loading', true)
      // kein Fehler
      context.app.$eventBus().$emit('errorLoading', false)
    }
    try {
      // Authentifizierung beim Server
      const dao = context.app.$dao()
      const response = await dao.authentifierUtilisateur('admin', 'admin')
      // Protokoll
      console.log('[authentification asyncData response=]', response)
      // Ergebnis
      const userAuthenticated = response.état === 200
      // Es wird vermerkt, ob der Benutzer authentifiziert ist oder nicht
      context.store.commit('replace', { userAuthenticated })
      // Der Store wird in der Sitzung gespeichert [nuxt]
      const session = context.app.$session()
      session.save(context)
      // Authentifizierungsfehler?
      if (!userAuthenticated) {
        // Der Fehler befindet sich in response.réponse
        throw new Error(response.réponse)
      }
      // Das Ergebnis wird zurückgegeben
      return { result: '[succès]' }
    } catch (e) {
      // Der Fehler wird gemeldet
      return { result: '[échec]', showErrorLoading: true, errorLoadingMessage: e.message }
    } finally {
      // Protokoll
      console.log('[authentification asyncData finished]')
      if (process.client) {
        // Ende der Wartezeit auf den Client [nuxt]
        context.app.$eventBus().$emit('loading', false)
      }
    }
  },
  // Lebenszyklus
  beforeCreate() {
    console.log('[authentification beforeCreate]')
  },
  created() {
    console.log('[authentification created]')
  },
  beforeMount() {
    console.log('[authentification beforeMount]')
  },
  mounted() {
    console.log('[authentification mounted]')
    // nur Kunde
    if (this.showErrorLoading) {
      console.log('[authentification mounted, showErrorLoading=true]')
      this.$eventBus().$emit('errorLoading', true, this.errorLoadingMessage)
    }
  }
}
</script>

Es gibt zwei Fälle, in denen die Seite [authentification] vom Client [nuxt] ausgeführt wird:

  1. Der Client [nuxt] wird ausgeführt, nachdem der Server [nuxt] die Seite [authentification] an den Browser des Clients [nuxt] gesendet hat;
  2. der Client [nuxt], weil der Benutzer auf den Link [Authentification] im Navigationsmenü geklickt hat:

Image

Betrachten wir zunächst den ersten Fall. In diesem Fall führt der Client [nuxt] die Funktion [asyncData] nicht aus. Er fügt die Elemente [result] und gegebenenfalls [showErrorLoading, errorLoadingMessage], die ihm der Server [nuxt] gesendet hat, in die Eigenschaften der Seite ein:

  • Die Eigenschaft [result] wird in Zeile 7 angezeigt;
  • die Eigenschaften [showErrorLoading, errorLoadingMessage] werden von der Methode [mounted] verwendet: In Zeile 79 wird die Eigenschaft [showErrorLoading] geprüft. Ist sie wahr, wird in Zeile 81 der Ereignisbus des Clients [nuxt] verwendet, um zu signalisieren, dass eine Fehlermeldung angezeigt werden muss;

Der Mechanismus zur Anzeige der Fehlermeldung wurde für die Seite [index] im Abschnitt „Link“ erläutert.

Fall 2 betrifft den Client [nuxt], der ausgeführt wird, wenn der Benutzer auf den Link [Authentification] klickt. In diesem Fall wird der Client [nuxt] eigenständig ausgeführt und nicht im Anschluss an den Server [nuxt]. Die Funktion [asyncData] wird dann ausgeführt. Wir geben nur die Details an, die sich von den Erläuterungen zur Seite unterscheiden, die vom Server [nuxt] ausgeführt wird:

  • Zeilen 28–33: Der Client [nuxt] fordert die Anzeige der Wartemeldung und das Ausblenden einer eventuell zuvor angezeigten Fehlermeldung an;
  • Zeile 36: Hier wird nun die Schicht [dao] des Clients [nuxt] abgerufen;
  • Zeilen 60–63: Der Client [nuxt] fordert an, die Anzeige der Wartemeldung zu beenden;
  • Sobald [asyncData] beendet ist, wird der Lebenszyklus der Seite durchlaufen. Die Funktion [mounted] in den Zeilen 76–83 wird ausgeführt. Ist ein Fehler aufgetreten, wird die Fehlermeldung angezeigt;

Hinweis: Um einen Fehler auszulösen, befolgen Sie die am Ende des Abschnitts „Link“ beschriebene Vorgehensweise für den Server [nuxt], verwenden Sie jedoch anstelle der Seite [authentification] – die Sie durch Eingabe von URL in die Adressleiste aufrufen würden – den Link [Authentification] aus dem Navigationsmenü. Dann wird der Client [nuxt] ausgeführt.

15.17. Die Seite [get-admindata]

Der Code der Seite [get-admindata] lautet wie folgt:


<!-- Ansicht „get-admindata“ -->
<template>
  <Layout :left="true" :right="true">
    <!-- Navigation -->
    <Navigation slot="left" />
    <!-- Meldung -->
    <b-alert slot="right" show variant="secondary"> Demande de [adminData] au serveur de calcul de l'impôt : {{ result }} </b-alert>
  </Layout>
</template>

<script>
/* eslint-disable no-console */

import Navigation from '@/components/navigation'
import Layout from '@/components/layout'

export default {
  name: 'GetAdmindata',
  // verwendete Komponenten
  components: {
    Layout,
    Navigation
  },
  // asynchrone Daten
  async asyncData(context) {
    // Protokoll
    console.log('[get-admindata asyncData started]')
    if (process.client) {
      // Wartezeit beginnt
      context.app.$eventBus().$emit('loading', true)
      // kein Fehler
      context.app.$eventBus().$emit('errorLoading', false)
    }
    try {
      // Daten werden angefordert [admindata]
      const response = await context.app.$dao().getAdminData()
      // Protokoll
      console.log('[get-admindata asyncData response=]', response)
      // Ergebnis
      const adminData = response.état === 1000 ? response.réponse : ''
      // Die Daten werden in den Speicher geschrieben
      context.store.commit('replace', { adminData })
      // Der Speicher wird in der Sitzung gespeichert [nuxt]
      const session = context.app.$session()
      session.save(context)
      // Ist ein Fehler aufgetreten?
      if (!adminData) {
        // Der Fehler befindet sich in response.réponse
        throw new Error(response.réponse)
      }
      // Der empfangene Wert wird zurückgegeben
      return { result: adminData }
    } catch (e) {
      // Der Fehler wird gemeldet
      return { result: '[échec]', showErrorLoading: true, errorLoadingMessage: e.message }
    } finally {
      // Protokoll
      console.log('[get-admindata asyncData finished]')
      if (process.client) {
        // Wartezeit beendet
        context.app.$eventBus().$emit('loading', false)
      }
    }
  },
  // Lebenszyklus
  beforeCreate() {
    console.log('[get-admindata beforeCreate]')
  },
  created() {
    console.log('[get-admindata created]')
  },
  beforeMount() {
    console.log('[get-admindata beforeMount]')
  },
  mounted() {
    console.log('[get-admindata mounted]')
    // Client
    if (this.showErrorLoading) {
      console.log('[get-admindata mounted, showErrorLoading=true]')
      this.$eventBus().$emit('errorLoading', true, this.errorLoadingMessage)
    }
  }
}
</script>

Diese Seite ist der Seite [authentification] sehr ähnlich. Die Erläuterungen gelten sowohl für die Ausführung durch den Server [nuxt] als auch für die Ausführung durch den Client [nuxt]. Es ist jedoch zu beachten, dass in Zeile 7 nicht wie zuvor „erfolgreich“ oder „fehlgeschlagen“ angezeigt wird, sondern der Wert der vom Steuerberechnungsserver empfangenen Daten (Zeile 52):

Image

Das oben gezeigte Ergebnis wird sowohl mit dem Server als auch mit dem Client [nuxt] erzielt. Um einen Fehler auszulösen, rufen Sie die Seite [get-admindata] über den Server oder den Client [nuxt] auf, ohne authentifiziert zu sein:

Image

15.18. Die Seite [fin-session]

Der Code der Seite lautet wie folgt:


<!-- Startseite -->
<template>
  <Layout :left="true" :right="true">
    <!-- Navigation -->
    <Navigation slot="left" />
    <!-- Meldung-->
    <b-alert slot="right" show variant="warning">Fin de la session avec le serveur de calcul de l'impôt : {{ result }} </b-alert>
  </Layout>
</template>

<script>
/* eslint-disable no-console */

import Navigation from '@/components/navigation'
import Layout from '@/components/layout'

export default {
  name: 'FinSession',
  // verwendete Komponenten
  components: {
    Layout,
    Navigation
  },
  // asynchrone Daten
  async asyncData(context) {
    // Protokoll
    console.log('[fin-session asyncData started]')
    // Kundenfall [nuxt]
    if (process.client) {
      // Wartezeit beginnt
      context.app.$eventBus().$emit('loading', true)
      // kein Fehler
      context.app.$eventBus().$emit('errorLoading', false)
    }
    try {
      // Eine neue Sitzung PHP wird beim Steuerberechnungsserver angefordert
      const dao = context.app.$dao()
      const response = await dao.finSession()
      // Protokoll
      console.log('[fin-session asyncData response=]', response)
      // Ist ein Fehler aufgetreten?
      if (response.état !== 400) {
        // Der Fehler befindet sich in response.réponse
        throw new Error(response.réponse)
      }
      // Der Server hat ein neues Sitzungs-Cookie gesendet: PHP
      // Es wird sowohl vom Server als auch vom Nuxt-Client abgerufen
      // Wenn dieser Code vom Client [nuxt] ausgeführt wird, muss das Sitzungs-Cookie PHP in die Nuxt-Sitzung gesetzt werden
      // damit das Plugin [plgDao] des Servers [nuxt] es abrufen und die Schicht [dao] mit
      //. Wenn dieser Code vom Server [nuxt] ausgeführt wird, muss das Sitzungs-Cookie PHP in die Nuxt-Sitzung
      // abgelegt werden, damit das Routing des Clients [nuxt] es abruft und an den Browser weiterleitet
      const phpSessionCookie = dao.getPhpSessionCookie()
      // wird im Store vermerkt, dass die Sitzung jSON gestartet wurde, und das Sitzungs-Cookie PHP wird gespeichert
      context.store.commit('replace', { jsonSessionStarted: true, phpSessionCookie, userAuthenticated: false, adminData: '' })
      // Der Speicher wird in der Sitzung [nuxt] gespeichert
      const session = context.app.$session()
      session.save(context)
      // Das Ergebnis wird zurückgegeben
      return { result: "[succès]. La session jSON reste initialisée mais vous n'êtes plus authentifié(e)." }
    } catch (e) {
      // Protokoll
      console.log('[fin-session asyncData error=]', e)
      // Der Fehler wird gemeldet
      return { result: '[échec]', showErrorLoading: true, errorLoadingMessage: e.message }
    } finally {
      // Protokoll
      console.log('[fin-session asyncData finished]')
      if (process.client) {
        // Wartezeit beendet
        context.app.$eventBus().$emit('loading', false)
      }
    }
  },
  // Lebenszyklus
  beforeCreate() {
    console.log('[fin-session beforeCreate]')
  },
  created() {
    console.log('[fin-session created]')
  },
  beforeMount() {
    console.log('[fin-session beforeMount]')
  },
  mounted() {
    console.log('[fin-session mounted]')
    // nur Client
    if (this.showErrorLoading) {
      console.log('[fin-session mounted, showErrorLoading=true]')
      this.$eventBus().$emit('errorLoading', true, this.errorLoadingMessage)
    }
  }
}
</script>

Der Code ist dem der vorherigen Seiten sehr ähnlich, und die Erläuterungen sind dieselben. Es ist lediglich auf einen Punkt einzugehen: Die asynchrone Operation in Zeile 38 bewirkt, dass der Steuerberechnungsserver ein neues Sitzungs-Cookie PHP sendet. Die Erläuterungen zur Handhabung dieses Cookies unterscheiden sich je nachdem, ob der Server oder der Client [nuxt] diesen Code ausführt.

Beginnen wir mit dem Server [nuxt]:

  • Zeile 37: Hier wird die Schicht [dao] des Servers [nuxt] instanziiert. Erinnern wir uns an den Code ihres Konstruktors:

// Konstruktor
  constructor(axios, phpSessionCookie) {
    // Axios-Bibliothek
    this.axios = axios
    // Wert des Sitzungs-Cookies
    this.phpSessionCookie = phpSessionCookie
    // Name des Sitzungs-Cookies des Servers PHP
    this.phpSessionCookieName = 'PHPSESSID'
}

In Zeile 1 ist zu sehen, dass der Konstruktor das aktuelle Sitzungs-Cookie PHP benötigt, also das zuletzt empfangene, sei es vom Server oder vom Client [nuxt];

  • Zeile 52: Der Server [nuxt] ruft das Cookie der neuen Sitzung PHP ab oder das alte Cookie, falls der Vorgang zum Beenden der Sitzung fehlgeschlagen ist;
  • Zeile 54: Das Sitzungs-Cookie PHP wird in den Speicher gestellt und anschließend in den Zeilen 56–57 in der Sitzung [nuxt] gespeichert;
  • Anschließend führt der Client [nuxt] die Seite [fin-session] mit den vom Server gesendeten Daten aus. Es ist bekannt, dass er die Funktion [asyncData] nicht ausführen wird;
  • letztendlich, nachdem der Server und der Client [nuxt] ihre Arbeit beendet haben, ist bekannt, dass sich das für den Austausch mit dem Steuerberechnungsserver erforderliche Cookie PHP in der Sitzung [nuxt] befindet;

Die Tatsache, dass sich das Cookie PHP in der Sitzung [nuxt] befindet, reicht für den Server aus, da seine Schicht [dao] es von dort abruft. Im Plugin [server/plgDao], das die Schicht [dao] des Servers initialisiert, wurde Folgendes geschrieben:


/* eslint-disable no-console */
// Es wird ein Zugriffspunkt auf die Schicht erstellt [Dao]
import Dao from '@/api/server/Dao'
export default (context, inject) => {
  // Axios-Konfiguration
  context.$axios.defaults.timeout = context.env.timeout
  context.$axios.defaults.baseURL = context.env.baseURL
  // Das Sitzungs-Cookie wird abgerufen
  const store = context.app.$session().value.store
  const phpSessionCookie = store ? store.phpSessionCookie : ''
  console.log('session=', context.app.$session().value, 'phpSessionCookie=', phpSessionCookie)
  // Instanziierung der Schicht [dao]
  const dao = new Dao(context.$axios, phpSessionCookie)
  // Einfügen einer Funktion [$dao] in den Kontext
  inject('dao', () => dao)
  // Protokollierung
  console.log('[fonction server $dao créée]')
}
  • Zeile 13: Die Schicht [dao] des Servers [nuxt] wird mit dem Sitzungs-Cookie PHP instanziiert, das aus der Sitzung [nuxt] (Zeilen 9–10) entnommen wurde;

Für den Client [nuxt] sieht die Sache anders aus. Tatsächlich sendet nicht er das Cookie, sondern der Browser, der ihn ausführt. Dieser Browser kennt jedoch das Cookie der neuen Sitzung PHP nicht, das vom Server [nuxt] empfangen wurde. Wenn man die Links des Navigationsmenüs [3] verwendet:

Image

erhält der Steuerberechnungsserver vom Browser ein veraltetes Sitzungs-Cookie „PHP“ und antwortet, dass diesem Cookie keine Sitzung „jSON“ zugeordnet ist. Wir müssen einen Weg finden, dem Browser das neue Sitzungs-Cookie „PHP“ zu übermitteln.

Dazu kann eine Routing-Middleware verwendet werden:

Image

Das Skript [client/routing] ist die Routing-Middleware, die in der Datei [nuxt.config] deklariert ist:


// Router
  router: {
    // Stammverzeichnis der Anwendung URL
    base: '/nuxt-12/',
    // Routing-Middleware
    middleware: ['routing']
},

Das Skript [middleware/routing] lautet wie folgt:


/* eslint-disable no-console */

// Wir importieren die Client-Middleware
import clientRouting from './client/routing'

export default function(context) {
  // Wer führt diesen Code aus?
  console.log('[middleware], process.server', process.server, ', process.client=', process.client)
  if (process.client) {
    // Client-Routing
    clientRouting(context)
  }
}
  • Zeilen 9–12: Es wird nur der Client mit einer in Zeile 4 importierten Funktion weitergeleitet;

Das Skript [middleware/client/routing] lautet wie folgt:


/* eslint-disable no-console */
export default function(context) {
  // Wer führt diesen Code aus?
  console.log('[middleware client], process.server', process.server, ', process.client=', process.client)
  // Verwaltung des Sitzungs-Cookies PHP im Browser
  // Das Sitzungs-Cookie PHP des Browsers muss mit dem in der Nuxt-Sitzung gefundenen identisch sein
  // Die Aktion [fin-session] erhält ein neues Cookie PHP (sowohl vom Server als auch vom Nuxt-Client)
  // Wenn der Server es empfängt, muss der Client es an den Browser weiterleiten
  // für seine eigenen Datenaustausche mit dem Server PHP
  // Hier handelt es sich um ein Client-Routing

  // Das Sitzungs-Cookie wird abgerufen: PHP
  const phpSessionCookie = context.store.state.phpSessionCookie
  if (phpSessionCookie) {
    // Falls vorhanden, wird das Sitzungs-Cookie PHP dem Browser zugewiesen
    document.cookie = phpSessionCookie
  }
}

Kehren wir zu der Situation unmittelbar nach der Ausführung der Seite [fin-session] durch den Server [nuxt] zurück:

Image

Wenn man auf einen der Links im Menü [3] klickt, übernimmt der Client [nuxt] die Steuerung. Da ein Seitenwechsel stattfindet, wird das Routing-Skript des Clients ausgeführt:

  • Zeile 13: Das Sitzungs-Cookie PHP wird im Speicher der Anwendung [nuxt] gefunden;
  • Zeile 14: Ist es nicht leer, wird es an den Browser übermittelt (Zeile 16). Ab diesem Zeitpunkt verfügt der Browser des Clients [nuxt] über das richtige Sitzungs-Cookie PHP;

Das Skript [client/routing] wird bei jedem Seitenwechsel des Clients [nuxt] ausgeführt. Der Skriptcode ist unabhängig von der Zielseite gültig: Meistens weist er dem Browser lediglich ein Sitzungs-Cookie PHP zu, das dieser bereits besitzt, außer in zwei Fällen:

  • unmittelbar nach dem Start der Anwendung, führt der Server [nuxt] die Seite [index] aus und erhält ein erstes Sitzungs-Cookie PHP, über das der Browser des Clients [nuxt] nicht verfügt;
  • wenn der Server [nuxt] die Seite [fin-session] wie gerade erläutert ausführt;

Betrachten wir nun den Fall, in dem die Seite [fin-session] ausschließlich vom Client [nuxt] ausgeführt wird, weil auf den entsprechenden Link im Navigationsmenü geklickt wurde. Nun ist es der Client [nuxt], der die Funktion [asyncData] ausführt:


try {
      // Eine neue Sitzung PHP wird beim Steuerberechnungsserver angefordert
      const dao = context.app.$dao()
      const response = await dao.finSession()
      // Protokoll
      console.log('[fin-session asyncData response=]', response)
      // Ist ein Fehler aufgetreten?
      if (response.état !== 400) {
        // Der Fehler befindet sich in response.réponse
        throw new Error(response.réponse)
      }
      // Der Server hat ein neues Sitzungs-Cookie gesendet: PHP
      // Es wird sowohl vom Server als auch vom Nuxt-Client abgerufen
      // Wenn dieser Code vom Client [nuxt] ausgeführt wird, muss das Sitzungs-Cookie PHP in die Nuxt-Sitzung gesetzt werden
      // damit das Plugin [plgDao] des Servers [nuxt] es abrufen und die Schicht [dao] mit
      //. Wenn dieser Code vom Server [nuxt] ausgeführt wird, muss das Sitzungs-Cookie PHP in die Nuxt-Sitzung
      // abgelegt werden, damit das Routing des Clients [nuxt] es abruft und an den Browser weiterleitet
      const phpSessionCookie = dao.getPhpSessionCookie()
      // wird im Store vermerkt, dass die Sitzung jSON gestartet wurde, und das Sitzungs-Cookie PHP wird gespeichert
      context.store.commit('replace', { jsonSessionStarted: true, phpSessionCookie, userAuthenticated: false, adminData: '' })
      // Der Speicher wird in der Sitzung [nuxt] gespeichert
      const session = context.app.$session()
      session.save(context)
      // Das Ergebnis wird zurückgegeben
      return { result: "[succès]. La session jSON reste initialisée mais vous n'êtes plus authentifié(e)." }
    } catch (e) {
      // Protokoll
      console.log('[fin-session asyncData error=]', e)
      // Der Fehler wird gemeldet
      return { result: '[échec]', showErrorLoading: true, errorLoadingMessage: e.message }
    } finally {
      // Protokoll
      console.log('[fin-session asyncData finished]')
      if (process.client) {
        // Wartezeit beendet
        context.app.$eventBus().$emit('loading', false)
      }
    }
  • Zeile 3: Hier wird die Schicht [dao] des Clients [nuxt] abgerufen;
  • Zeile 18: Das Sitzungs-Cookie PHP, das von der Schicht [dao] des Clients [nuxt] abgerufen wurde, wird gespeichert, in den Speicher (Zeile 20) abgelegt und anschließend in der Sitzung [nuxt] gespeichert (Zeilen 22–23);
  • ab diesem Punkt läuft alles reibungslos, da bekannt ist, dass die Schicht [dao] des Servers [nuxt] das Sitzungs-Cookie PHP aus der Sitzung [nuxt] abruft;

15.19. Exécution

Um dieses Beispiel auszuführen, muss vor der Ausführung darauf geachtet werden, das Sitzungs-Cookie [nuxt] und das Cookie PHP aus dem Browser zu löschen, in dem der Client [nuxt] ausgeführt wird, um von einer sauberen Ausgangssituation auszugehen. Nachfolgend ein Beispiel mit dem Chrome-Browser:

Image

15.20. Conclusion

Dieses Beispiel war besonders komplex. Es vereinte Kenntnisse aus den vorherigen Beispielen: Persistenz des Stores in einer Sitzung ([nuxt]), Plugins zur Funktionseinbindung, Routing-Middleware sowie Fehlerbehandlung bei asynchronen Operationen. Die Komplexität wurde dadurch erhöht, dass der Benutzer sowohl die Links im Navigationsmenü nutzen als auch URL manuell eingeben können sollte, ohne dass die Anwendung dabei abstürzt. Dazu mussten wir untersuchen, wie sich jede Seite verhält, je nachdem, ob sie vom Client oder vom Server [nuxt] ausgeführt wird.

Diese einheitliche Verhaltensweise von Client und Server [nuxt] ist nicht zwingend erforderlich. Man kann den häufigen Fall betrachten, in dem:

  • die erste Seite vom Server [nuxt] bereitgestellt wird;
  • alle folgenden Seiten vom Client [nuxt] ausgeliefert werden, der dann im Modus [SPA] arbeitet;

Dennoch muss auch in diesem Fall überprüft werden, wie die Ausführung aller Seiten durch den Server [nuxt] aussieht, da Suchmaschinen, die diese Seiten anfordern, genau diese Ergebnisse erhalten werden.