15. Esempio [nuxt-12]: richieste a HTTP con axios
15.1. Présentation
In questo nuovo esempio, scopriremo come, nelle funzioni [asyncData], sia possibile effettuare richieste HTTP utilizzando la libreria [axios]. Inoltre, utilizzeremo nozioni già acquisite:
- l’utilizzo dei plugin dell’esempio [nuxt-06]:
- la persistenza dello store in un cookie di sessione dell’esempio [nuxt-06];
- il controllo della navigazione con i middleware dell’esempio [nuxt-09];
- la gestione degli errori dell'esempio [nuxt-11];
L’architettura dell’esempio sarà la seguente:

- l’applicazione [nuxt] sarà memorizzata sul server [node.js] [3], scaricata dal browser [1] che la eseguirà successivamente;
- sia il client [nuxt] [1] che il server [nuxt] [3] invieranno richieste HTTP al server dati [2]. Questo server sarà il server di calcolo delle imposte sviluppato nella sezione PHP 7. Utilizzeremo la sua ultima versione, la versione 14, con le richieste CORS autorizzate;
L’architettura dell’esempio può essere semplificata come segue:

- in [1], il server [node.js] fornisce le pagine [nuxt] al browser [2]. È il livello [web] [8] del server che fornisce queste pagine. Per fornire la pagina, il server potrebbe aver richiesto dati esterni al server di dati [3]. È il livello [DAO] [9] che effettua le richieste HTTP necessarie;
- ad ogni richiesta di pagina al server [node.js][1], il browser [2] riceve l’intera applicazione [nuxt], che verrà quindi eseguita in modalità SPA. Il blocco [UI] (Interfaccia utente) [4] presenta all’utente le pagine [vue.js]. Le azioni dell’utente o il ciclo di vita naturale delle pagine possono provocare richieste di dati esterni al server di dati [3]. È quindi il livello [DAO] [5] che effettua le richieste HTTP necessarie;
15.2. Struttura ad albero del progetto

15.3. Il file di configurazione [nuxt.config.js]
Il progetto sarà controllato dal file [nuxt.config.js] seguente:
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: [
// 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) { }
},
// directory del codice sorgente
srcDir: 'nuxt-12',
// router
router: {
// radice dell'applicazione URL
base: '/nuxt-12/',
// middleware di routing
middleware: ['routing']
},
// server
server: {
// porta di servizio, 3000 per impostazione predefinita
port: 81,
// indirizzi di rete in ascolto, per impostazione predefinita localhost: 127.0.0.1
// 0.0.0.0 = tutti gli indirizzi di rete del computer
host: 'localhost'
},
// ambiente
env: {
// configurazione di Axios
timeout: 2000,
withCredentials: true,
baseURL: 'http://localhost/php7/scripts-web/impots/version-14',
// configurazione del cookie di sessione [nuxt]
maxAge: 60 * 5
}
}
- riga 22: gestiamo autonomamente l'avviso di attesa della fine di un'azione asincrona;
- riga 31: utilizzeremo vari plugin specializzati o per il client o per il server, ma non per entrambi contemporaneamente;
- riga 52: il modulo [axios] è integrato in [nuxt]. Ciò comporterà che l’oggetto [axios], che effettuerà le richieste HTTP dell’applicazione [nuxt] al server PHP per il calcolo delle imposte, sarà disponibile in [context.$axios];
- riga 54: il modulo [cookie-universal-nuxt] ci consentirà di salvare la sessione [nuxt] in un cookie;
- riga 60: la proprietà [axios] ci permette di configurare il modulo [@nuxtjs/axios] della riga 52. Non utilizzeremo questa opzione, preferendo invece la proprietà [env] della riga 88;
- riga 90: tempo massimo di attesa per la risposta del server di calcolo delle imposte;
- riga 91: necessaria per il client [nuxt] - autorizza l'uso dei cookie negli scambi con il server di calcolo delle imposte;
- riga 92: URL di base del server di calcolo delle imposte;
- riga 94: durata della sessione Nuxt (5 minuti);
- riga 77: la navigazione tra client e server [nuxt] sarà controllata da un middleware di routing;
15.4. Il livello [UI] dell’applicazione

Concederemo all’applicazione [nuxt] l’accesso a API del server di calcolo delle imposte tramite la seguente vista:

- in [2], il menu che consente di accedere a API del server di calcolo delle imposte:
- [Authentification]: corrisponde alla pagina [authentification]. Questa pagina invia una richiesta di autenticazione al server di calcolo delle imposte con le credenziali [admin, admin], che al momento sono le uniche autorizzate. Il risultato visualizzato è analogo a quello di [3];
- [Requête AdminData]: corrisponde alla pagina [get-admindata]. Questa pagina richiede al server di calcolo delle imposte i dati, qui denominati [adminData], che consentono il calcolo dell’imposta. Il risultato visualizzato è analogo a [3];
- [Fin session impôt]: corrisponde alla pagina [fin-session]. Questa pagina invia una richiesta di chiusura della sessione PHP al server di calcolo dell’imposta. Il server annulla quindi la sessione corrente PHP e ne inizializza una nuova vuota;
15.5. I livelli [dao] dell’applicazione [nuxt]
Come indicato in precedenza, l’architettura dell’applicazione [nuxt] sarà la seguente:

- in [1], il server [node.js] invia le pagine [nuxt] al browser [2]. È il livello [web] [8] del server che fornisce queste pagine. Per fornire la pagina, il server potrebbe aver richiesto dati esterni al server di dati [3]. È il livello [DAO] [9] che effettua le richieste HTTP necessarie;
- ad ogni richiesta di pagina al server [node.js][1], il browser [2] riceve l’intera applicazione [nuxt], che verrà quindi eseguita in modalità SPA. Il blocco [UI] (Interfaccia utente) [4] presenta all’utente le pagine [vue.js]. Le azioni di quest’ultimo o il ciclo di vita delle pagine possono provocare richieste di dati esterni al server di dati [3]. È il livello [DAO] [5] che effettua quindi le richieste HTTP necessarie;
Utilizzeremo la versione 14 del server di calcolo delle imposte sviluppato nel documento |Introduzione al linguaggio PHP7 attraverso un esempio|. Utilizzeremo solo una parte della sua API (Application Programming Interface) jSON:
Richiesta | Risposta |
| |
| |
| |
| |
15.5.1. Il livello [dao] del server [nuxt]

Il server [node.js] [1] utilizzerà il livello [dao] descritto nel documento |Introduzione al framework VUE.JS attraverso un esempio|. Ne riportiamo qui il codice:
'use strict';
// importazioni
import qs from 'qs'
class Dao {
// costruttore
constructor(axios) {
this.axios = axios;
// cookie di sessione
this.sessionCookieName = "PHPSESSID";
this.sessionCookie = '';
}
// inizializzazione della sessione
async initSession() {
// opzioni della richiesta HHTP [get /main.php?action=init-session&type=json]
const options = {
method: "GET",
// parametri di URL
params: {
action: 'init-session',
type: 'json'
}
};
// esecuzione della query HTTP
return await this.getRemoteData(options);
}
async authentifierUtilisateur(user, password) {
// opzioni della richiesta HHTP [post /main.php?action=authentifier-utilisateur]
const options = {
method: "POST",
headers: {
'Content-type': 'application/x-www-form-urlencoded',
},
// corpo del POST
data: qs.stringify({
user: user,
password: password
}),
// parametri dell'URL
params: {
action: 'authentifier-utilisateur'
}
};
// esecuzione della richiesta HTTP
return await this.getRemoteData(options);
}
async getAdminData() {
// opzioni della richiesta HHTP [get /main.php?action=get-admindata]
const options = {
method: "GET",
// parametri della query URL
params: {
action: 'get-admindata'
}
};
// esecuzione della query HTTP
const data = await this.getRemoteData(options);
// risultato
return data;
}
async getRemoteData(options) {
// per il cookie di sessione
if (!options.headers) {
options.headers = {};
}
options.headers.Cookie = this.sessionCookie;
// esecuzione della richiesta HTTP
let response;
try {
// richiesta asincrona
response = await this.axios.request('main.php', options);
} catch (error) {
// il parametro [error] è un'istanza di eccezione - può assumere diverse forme
if (error.response) {
// la risposta del server è contenuta in [error.response]
response = error.response;
} else {
// l'errore viene generato nuovamente
throw error;
}
}
// la risposta è l'insieme della risposta HTTP del server (intestazioni HTTP + la risposta stessa)
// si recupera il cookie di sessione, se presente
const setCookie = response.headers['set-cookie'];
if (setCookie) {
// setCookie è un array
// si cerca il cookie di sessione in questo array
let trouvé = false;
let i = 0;
while (!trouvé && i < setCookie.length) {
// si cerca il cookie di sessione
const results = RegExp('^(' + this.sessionCookieName + '.+?);').exec(setCookie[i]);
if (results) {
// si memorizza il cookie di sessione
// eslint-disable-next-line require-atomic-updates
this.sessionCookie = results[1];
// trovato
trouvé = true;
} else {
// elemento successivo
i++;
}
}
}
// la risposta del server si trova in [response.data]
return response.data;
}
}
// esportazione della classe
export default Dao;
- tutti i metodi del livello [dao] restituiscono l’oggetto inviato dal server di dati [{action : ‘xx’, état : nn, réponse : {...}] con:
- [action]: il nome dell’azione eseguita dal server dati;
- [état]: indicatore numerico:
- [initSession]: stato=700 per una risposta senza errori;
- [authentifierUtilisateur]: stato=200 per una risposta senza errori;
- [getAdminData]: stato=1000 per una risposta senza errori;
- [fin-session]: stato=400 per una risposta senza errori;
- [réponse]: risposta associata all'indicatore numerico [état]. Può variare in base a tale indicatore numerico;
Esaminiamo il costruttore della classe [Dao]:
// costruttore
constructor(axios) {
this.axios = axios;
// cookie di sessione
this.sessionCookieName = "PHPSESSID";
this.sessionCookie = '';
}
- riga 2: l’oggetto [axios] fornito come argomento al costruttore è fornito dal codice chiamante. È questo che effettuerà le richieste HTTP;
- riga 5: il nome del cookie di sessione inviato dal server dati è scritto come PHP;
- riga 6: il cookie di sessione scambiato tra il livello [dao] e il server dati. Questo viene inizializzato dalla funzione [getRemoteData] alle righe 67-113;
Per quanto riguarda il cookie di sessione, dobbiamo considerare due livelli [dao] distinti:
- quello del browser;
- quello del server;
Dovremo gestire tre cookie di sessione:
- quello scambiato tra il client [nuxt] e il server PHP 7;
- quello scambiato tra il server [nuxt] e il server PHP 7;
- quello scambiato tra il client [nuxt] e il server [nuxt];
Faremo in modo che il cookie di sessione con il server PHP sia lo stesso sia per il client che per il server [nuxt]. Chiameremo questo cookie «cookie di sessione PHP». Questo cookie è quello dei casi 1 e 2. Chiameremo «cookie di sessione [nuxt]» il cookie del caso 3. Avremo quindi due sessioni:
- una sessione PHP con il cookie di sessione PHP;
- una sessione [nuxt] con il cookie di sessione [nuxt];
Perché utilizzare lo stesso cookie per le sessioni PHP del client e del browser [nuxt]? Vogliamo che l’applicazione possa comunicare con il server PHP indipendentemente dal fatto che si tratti del client o del server [nuxt]:
- se un’azione A del server [nuxt] porta il server PHP in uno stato E, tale stato si riflette nella sessione PHP gestita dal server PHP;
- utilizzando lo stesso cookie di sessione PHP del server, un’azione B del client [nuxt] che seguisse l’azione A del server [nuxt] troverebbe il server PHP nellostato E lasciato dal server [nuxt] e potrebbe quindi avvalersi del lavoro già svolto dal server [nuxt];
- se dopo l’azione B del client [nuxt] segue un’azione C del server [nuxt], per lo stesso motivo di prima, tale azione potrà avvalersi del lavoro svolto dall’azione B del client [nuxt];
Affinché il browser del cliente [nuxt] possa comunicare con il server PHP per il calcolo dell’imposta, utilizzeremo la versione 14 di tale server, che consente le chiamate tra domini, ovvero quelle da un browser al server PHP. Le chiamate dal server [nuxt] al server PHP non sono invece chiamate interdominio. Questo concetto esiste solo per le chiamate effettuate da un browser.
Torniamo al codice del costruttore della classe [Dao] precedente:
// costruttore
constructor(axios) {
this.axios = axios;
// cookie di sessione
this.sessionCookieName = "PHPSESSID";
this.sessionCookie = '';
}
- le righe 5 e 6 corrispondono al cookie di sessione PHP con il server di calcolo delle imposte;
La gestione del cookie di sessione PHP sopra indicata non è adeguata per il server [nuxt]: il suo livello [dao] viene istanziato ad ogni nuova richiesta effettuata al server [nuxt]. Si ricorda infatti che richiedere una pagina al server [nuxt] equivale a reinizializzare l’applicazione [nuxt]. Pertanto, quando al termine della prima richiesta effettuata al server di dati dal server [nuxt], il cookie di sessione PHP del livello [dao] viene inizializzato, tale valore va perso durante la successiva richiesta HTTP dello stesso server [nuxt], poiché nel frattempo il suo livello [dao] è stato ricreato, il costruttore è stato rieseguito e il cookie di sessione PHP è stato reinizializzato con la stringa vuota (riga 6);
Una soluzione consiste nell’utilizzare un altro costruttore per il livello [dao] del server:
// costruttore
constructor(axios, phpSessionCookie) {
// libreria axios
this.axios = axios
// valore del cookie di sessione
this.phpSessionCookie = phpSessionCookie
// nome del cookie di sessione del server PHP
this.phpSessionCookieName = 'PHPSESSID'
}
- riga 2: questa volta il cookie di sessione PHP verrà fornito al costruttore del livello [dao] del server dati;
In che modo il server [nuxt] potrà fornire questo cookie di sessione PHP al costruttore del proprio livello [dao]? Memorizzeremo il cookie di sessione PHP nel cookie di sessione [nuxt] scambiato tra il browser e il server [nuxt]. Il processo è il seguente:
- viene avviata l’applicazione [nuxt];
- quando il server [nuxt] effettua la sua prima richiesta HTTP al server PHP, memorizza il cookie di sessione PHP che ha ricevuto nel cookie di sessione [nuxt] che scambia con il client [nuxt];
- il browser che ospita il client [nuxt] riceve questo cookie di sessione [nuxt] e lo rinvia quindi sistematicamente ad ogni nuova richiesta al server [nuxt];
- quando il server [nuxt] dovrà effettuare una nuova richiesta al server PHP, ritroverà il cookie di sessione PHP all’interno del cookie di sessione [nuxt] che il browser gli avrà inviato. Lo invierà quindi al server PHP;
Esistono effettivamente due cookie di sessione e non bisogna confonderli:
- il cookie di sessione [nuxt] scambiato tra il server [nuxt] e il browser del cliente [nuxt];
- il cookie di sessione PHP scambiato tra il server [nuxt] e il server PHP oppure tra il client [nuxt] e il server PHP;
Torniamo ora al codice del metodo della classe [Dao]. Esso non include una funzione per chiudere la sessione PHP con il server di calcolo delle imposte. Aggiungiamo questa:
// fine della sessione di calcolo delle imposte
async finSession() {
// opzioni della richiesta HHTP [get /main.php?action=fin-session]
const options = {
method: 'GET',
// parametri di URL
params: {
action: 'fin-session'
}
}
// esecuzione della richiesta HTTP
const data = await this.getRemoteData(options)
// risultato
return data
}
Durante i test, si scopre che la funzione [getRemoteData] chiamata alla riga 12 non è adatta al metodo [finSession]:
async getRemoteData(options) {
// per il cookie di sessione
if (!options.headers) {
options.headers = {};
}
options.headers.Cookie = this.sessionCookie;
// esecuzione della richiesta HTTP
let response;
try {
// richiesta asincrona
response = await this.axios.request('main.php', options);
} catch (error) {
// il parametro [error] è un'istanza di eccezione - può assumere diverse forme
if (error.response) {
// la risposta del server è contenuta in [error.response]
response = error.response;
} else {
// l'errore viene generato nuovamente
throw error;
}
}
// la risposta è l'insieme della risposta HTTP del server (intestazioni HTTP + la risposta stessa)
// si recupera il cookie di sessione, se presente
const setCookie = response.headers['set-cookie'];
if (setCookie) {
// setCookie è un array
// si cerca il cookie di sessione in questo array
let trouvé = false;
let i = 0;
while (!trouvé && i < setCookie.length) {
// si cerca il cookie di sessione
const results = RegExp('^(' + this.sessionCookieName + '.+?);').exec(setCookie[i]);
if (results) {
// si memorizza il cookie di sessione
// eslint-disable-next-line require-atomic-updates
this.sessionCookie = results[1];
// trovato
trouvé = true;
} else {
// elemento successivo
i++;
}
}
}
// la risposta del server è in [response.data]
return response.data;
}
- righe 30-43: si cerca il cookie [PHPSESSID=xxx]. Se lo si trova, viene memorizzato nella classe (riga 36);
Questo codice non è compatibile con il nuovo metodo [finSession] poiché, nell’azione [fin-session], il server PHP invia due cookie con il nome [PHPSESSID]. Ecco un esempio ottenuto con un client [Postman]:

- in [1], la richiesta del client [Postman];
- in [3], la risposta del server PHP;
- in [4], le intestazioni HTTP della risposta del server PHP;

- in [5], il server PHP indica innanzitutto di aver eliminato la sessione corrente PHP;
- in [6], il server PHP invia il cookie della nuova sessione PHP;
Con il codice attuale, la funzione [getRemoteData] recupera il cookie [5], mentre è il cookie [6] che deve essere memorizzato.
È quindi necessario modificare il codice della funzione [getRemoteData]:
async getRemoteData(options) {
// esiste un cookie di sessione PHP?
if (this.phpSessionCookie) {
// Ci sono delle intestazioni?
if (!options.headers) {
// si crea un oggetto vuoto
options.headers = {}
}
// intestazione del cookie di sessione PHP
options.headers.Cookie = this.phpSessionCookie
}
// esecuzione della richiesta HTTP
let response
try {
// richiesta asincrona
response = await this.axios.request('main.php', options)
} catch (error) {
// il parametro [error] è un'istanza di eccezione - può assumere diverse forme
if (error.response) {
// la risposta del server si trova in [error.response]
response = error.response
} else {
// l'errore viene generato nuovamente
throw error
}
}
// la risposta è l'insieme della risposta HTTP del server (intestazioni HTTP + la risposta stessa)
// si cerca il cookie di sessione PHP tra i cookie ricevuti
// tutti i cookie ricevuti
const cookies = response.headers['set-cookie']
if (cookies) {
// i cookie sono un array
// si cerca il cookie di sessione PHP in questo array
let trouvé = false
let i = 0
while (!trouvé && i < cookies.length) {
// si cerca il cookie di sessione PHP
const results = RegExp('^(' + this.phpSessionCookieName + '.+?)$').exec(cookies[i])
if (results) {
// si memorizza il cookie di sessione PHP
const phpSessionCookie = results[1]
// è presente al suo interno la stringa [deleted]?
const results2 = RegExp(this.phpSessionCookieName + '=deleted').exec(phpSessionCookie)
if (!results2) {
// si ha il cookie di sessione corretto PHP
this.phpSessionCookie = phpSessionCookie
// è stato trovato
trouvé = true
} else {
// elemento successivo
i++
}
} else {
// elemento successivo
i++
}
}
}
// la risposta del server è in [response.data]
return response.data
}
- riga 41: è stato trovato un cookie con il nome [PHPSESSID]. Lo si memorizza localmente;
- riga 43: si verifica se nel cookie salvato è presente la stringa [PHPSESSID=deleted];
- riga 46: se la risposta è no, significa che è stato trovato il cookie corretto [PHPSESSID]. Lo si memorizza nella classe;
Dopo la funzione [getRemoteData], il cookie di sessione PHP viene memorizzato nella classe, in [this.phpSessionCookie]. Abbiamo detto che la classe viene istanziata ad ogni nuova richiesta HTTP dal server [nuxt]. Il cookie di sessione PHP deve quindi essere estratto dalla classe. A tal fine, si aggiunge un nuovo metodo alla classe:
// accesso al cookie di sessione PHP
getPhpSessionCookie() {
return this.phpSessionCookie
}
- il server [nuxt] richiede un’azione al proprio livello [dao] fornendo il cookie di sessione PHP al suo costruttore, se ne possiede uno;
- una volta eseguita l’azione, il server [nuxt] recupera il cookie di sessione PHP memorizzato dal livello [dao] utilizzando il metodo [getPhpSessionCookie] precedente. Questo cookie può essere lo stesso del precedente oppure un altro. Quest’ultimo caso si verifica in due occasioni:
- durante l’esecuzione del metodo [initSession] (in precedenza non era presente alcun cookie di sessione PHP);
- durante l’esecuzione del metodo [finSession] (il server PHP modifica il cookie di sessione PHP);
Da notare una particolarità relativa al cookie di sessione PHP. Il server [nuxt] non riceve sempre questo cookie dal server PHP. Infatti, quest’ultimo lo invia solo una volta. Successivamente non lo invia più. Osservando il codice di [getRemoteData] e quello di [getPhpSessionCookie], si noterà che quando il server PHP non invia alcun cookie di sessione, la funzione [getPhpSessionCookie] restituisce il cookie di sessione PHP fornito al costruttore. È così che il server invia sempre al server PHP l’ultimo cookie di sessione PHP che quest’ultimo gli ha inviato.
15.5.2. Il livello [dao] del client [nuxt]

Per il client [nuxt] in esecuzione in un browser, si riprende il codice della classe [Dao] dal documento |Introduzione al framework VUE.JS con un esempio|:
"use strict";
// importazioni
import qs from "qs";
class Dao {
// costruttore
constructor(axios) {
this.axios = axios;
}
// inizializzazione sessione
async initSession() {
// opzioni della richiesta HHTP [get /main.php?action=init-session&type=json]
const options = {
method: "GET",
// parametri di URL
params: {
action: "init-session",
type: "json"
}
};
// esecuzione della query HTTP
return await this.getRemoteData(options);
}
async authentifierUtilisateur(user, password) {
// opzioni della query HHTP [post /main.php?action=authentifier-utilisateur]
const options = {
method: "POST",
headers: {
"Content-type": "application/x-www-form-urlencoded"
},
// corpo del POST
data: qs.stringify({
user: user,
password: password
}),
// parametri di URL
params: {
action: "authentifier-utilisateur"
}
};
// esecuzione della query HTTP
return await this.getRemoteData(options);
}
async getAdminData() {
// opzioni della richiesta HHTP [get /main.php?action=get-admindata]
const options = {
method: "GET",
// parametri di URL
params: {
action: "get-admindata"
}
};
// esecuzione della query HTTP
const data = await this.getRemoteData(options);
// risultato
return data;
}
async getRemoteData(options) {
// esecuzione della richiesta HTTP
let response;
try {
// richiesta asincrona
response = await this.axios.request("main.php", options);
} catch (error) {
// il parametro [error] è un'istanza di eccezione - può assumere diverse forme
if (error.response) {
// la risposta del server è contenuta in [error.response]
response = error.response;
} else {
// si ripete l'errore
throw error;
}
}
// la risposta è l'insieme della risposta HTTP del server (intestazioni HTTP + la risposta stessa)
// la risposta del server si trova in [response.data]
return response.data;
}
}
// esportazione della classe
export default Dao;
Questo codice si distingue dal livello [dao] del server [nuxt] in quanto non gestisce il cookie di sessione PHP con il server di calcolo delle imposte: è il browser a farlo.
Come abbiamo fatto per il livello [dao] del server [nuxt], aggiungeremo un metodo [finSession]:
// fine della sessione di calcolo dell'imposta
async finSession() {
// opzioni della richiesta HHTP [get /main.php?action=fin-session]
const options = {
method: 'GET',
// parametri di URL
params: {
action: 'fin-session'
}
}
// esecuzione della query HTTP
const data = await this.getRemoteData(options)
// risultato
return data
}
Quando il client [nuxt] esegue questo metodo, riceve, come il server [nuxt], due cookie di sessione PHP. In realtà è il browser a riceverli e gestisce correttamente la situazione: conserva solo il cookie della nuova sessione PHP avviata dal server di calcolo delle imposte. Pertanto, alla successiva richiesta del client [nuxt] al server PHP, il cookie di sessione PHP sarà corretto, poiché è il browser a inviarlo. C'è tuttavia un problema: il server [nuxt] non è a conoscenza del fatto che il cookie di sessione PHP sia cambiato. Nelle sue comunicazioni con il server PHP, invierà quindi un cookie di sessione PHP che non esiste più e si verificheranno dei problemi. Il client [nuxt] dovrebbe avvisare il server [nuxt] che il cookie di sessione PHP è cambiato e trasmetterglielo. Sappiamo come può farlo: tramite il cookie di sessione [nuxt], il cookie scambiato tra il client e il server [nuxt]. Il client [nuxt] ha almeno due modi per recuperare il nuovo cookie di sessione PHP:
- richiedendolo al browser;
- utilizzando il metodo [getRemoteData] del server, che sa come recuperare il nuovo cookie di sessione PHP;
Utilizzeremo la seconda soluzione poiché è già pronta all’uso. Il metodo [getRemoteData] del client [nuxt] diventa quindi il seguente:
async getRemoteData(options) {
// esecuzione della richiesta HTTP
let response
try {
// richiesta asincrona
response = await this.axios.request('main.php', options)
} catch (error) {
// il parametro [error] è un'istanza di eccezione - può assumere diverse forme
if (error.response) {
// la risposta del server si trova in [error.response]
response = error.response
} else {
// l'errore viene generato nuovamente
throw error
}
}
// la risposta è l'insieme della risposta HTTP del server (intestazioni HTTP + la risposta stessa)
// si cerca il cookie di sessione PHP tra i cookie ricevuti
// tutti i cookie ricevuti
const cookies = response.headers['set-cookie']
if (cookies) {
// i cookie sono un array
// si cerca il cookie di sessione PHP in questo array
let trouvé = false
let i = 0
while (!trouvé && i < cookies.length) {
// si cerca il cookie di sessione PHP
const results = RegExp('^(' + this.phpSessionCookieName + '.+?)$').exec(cookies[i])
if (results) {
// si memorizza il cookie di sessione PHP
const phpSessionCookie = results[1]
// è presente al suo interno la stringa [deleted]?
const results2 = RegExp(this.phpSessionCookieName + '=deleted').exec(phpSessionCookie)
if (!results2) {
// si ha il cookie di sessione corretto PHP
this.phpSessionCookie = phpSessionCookie
// abbiamo trovato
trouvé = true
} else {
// elemento successivo
i++
}
} else {
// elemento successivo
i++
}
}
}
// la risposta del server è in [response.data]
return response.data
}
In [getRemoteData] abbiamo mantenuto solo il codice che utilizza la risposta del server PHP per individuare il cookie di sessione PHP. Non è stato mantenuto il codice che includeva il cookie di sessione PHP nella richiesta al server PHP, poiché se ne occupa il browser che ospita il client [nuxt].
Una volta che il cookie di sessione PHP è stato ottenuto dal client [nuxt], esso deve essere inserito nella sessione [nuxt] affinché il server [nuxt] possa avvalersene. Non è il livello [dao] a occuparsene, ma esso fornisce l’accesso, tramite un metodo, al cookie di sessione PHP che ha memorizzato:
// accesso al cookie di sessione PHP
getPhpSessionCookie() {
return this.phpSessionCookie
}
La funzione [getPhpSessionCookie] non restituisce sempre un cookie di sessione valido:
- occorre ricordare che il livello [dao] del client [nuxt] è persistente. Viene istanziato una volta e rimane poi in memoria;
- finché il server PHP non invia un cookie di sessione PHP al client [nuxt], la funzione [getPhpSessionCookie] del client [nuxt] restituisce il valore [undefined];
- quando il server PHP invia un cookie di sessione PHP al client [nuxt], quest’ultimo viene memorizzato in [this.phpSessionCookie] e vi rimarrà finché non verrà sostituito da un nuovo cookie di sessione PHP inviato dal server PHP. La funzione [getPhpSessionCookie] del client [nuxt] restituisce quindi l’ultimo cookie di sessione PHP ricevuto;
Il livello [dao] del client [nuxt] differisce da quello del server [nuxt] solo per un aspetto: non invia direttamente il cookie di sessione PHP, poiché è il browser a farlo. Tuttavia, si è preferito mantenere due livelli [dao] distinti, poiché i ragionamenti che portano alle rispettive implementazioni sono diversi.
15.6. La sessione [nuxt]
![]()
La sessione [nuxt] (tra client e server Nuxt) sarà incapsulata nel seguente oggetto [session]:
/* eslint-disable no-console */
// definizione della sessione
const session = {
// contenuto della sessione
value: {
// store non inizializzato
initStoreDone: false,
// valore dello store Vuex
store: ''
},
// salvataggio della sessione in un cookie
save(context) {
// salvataggio dello store nella sessione
this.value.store = context.store.state
console.log('nuxt-session save=', this.value)
// salvataggio del valore della sessione
context.app.$cookies.set('nuxt-session', this.value, { path: context.base, maxAge: context.env.maxAge })
},
// reset della sessione
reset(context) {
console.log('nuxt-session reset')
// reset dello store
context.store.commit('reset')
// salvataggio del nuovo store nella sessione e salvataggio della sessione
this.save(context)
}
}
// esportazione della sessione
export default session
- righe 5-10: la sessione ha una sola proprietà [value] con due sottoproprietà:
- [initStoreDone], che indica se lo store è stato inizializzato o meno;
- [store]: il valore [store.state] dello store Vuex dell’applicazione;
- righe 12-18: il metodo [save] serve a salvare la sessione [nuxt] in un cookie. Qui si utilizza la libreria [cookie-universal-nuxt] per gestire il cookie. Si noti il nome del cookie della sessione [nuxt]: [nuxt-session] (riga 17);
- righe 20-26: il metodo [reset] reinizializza la sessione [nuxt];
- riga 23: lo store Vuex viene reinizializzato e poi salvato nella sessione, riga 25;
15.7. I plugin di gestione della sessione [nuxt]

15.7.1. Il plugin di gestione della sessione [nuxt] di serveur [nuxt]
All'avvio dell'applicazione, il primo a entrare in funzione è il server [nuxt]. È quindi lui che inizializzerà la sessione [nuxt]. Lo script [server/plgSession] è il seguente:
/* eslint-disable no-console */
// importazione della sessione
import session from '@/entities/session'
export default (context, inject) => {
// gestione della sessione sul server
console.log('[plugin server plgSession]')
// Esiste già una sessione?
const value = context.app.$cookies.get('nuxt-session')
if (!value) {
// nuova sessione
console.log("[plugin server plgSession], démarrage d'une nouvelle session")
} else {
// sessione esistente
console.log("[plugin server plgSession], reprise d'une session existante")
session.value = value
}
// si inietta una funzione in [context, Vue] che renderà la sessione corrente
inject('session', () => session)
}
- riga 4: si importa il codice della sessione [nuxt];
- riga 11: si recupera il valore del cookie della sessione [nuxt];
- righe 12-15: se il cookie della sessione [nuxt] non esistesse, allora la sessione [nuxt] importata alla riga 4 è sufficiente. Non c’è altro da fare;
- righe 15-19: se il cookie della sessione [nuxt] esistesse, allora alla riga 18 se ne memorizza il valore nella sessione importata alla riga 4;
- riga 22: la sessione è stata inizializzata o ripristinata. La si rende disponibile tramite la funzione [$session];
15.7.2. Il plugin di gestione della sessione [nuxt] del client [nuxt]
Lo script [client/plgSession] è il seguente:
/* eslint-disable no-console */
// importazione della sessione
import session from '@/entities/session'
export default (context, inject) => {
// gestione della sessione del cliente
console.log('[plugin client plgSession], reprise de la session [nuxt] du serveur')
// si recupera la sessione esistente dal server Nuxt
session.value = context.app.$cookies.get('nuxt-session')
// si inserisce una funzione in [context, Vue] che renderà la sessione corrente
inject('session', () => session)
}
- riga 4: viene importata la sessione [nuxt];
- riga 10: si recupera la sessione corrente [nuxt] dal cookie [nuxt-session];
- riga 13: si restituisce la sessione [nuxt] importata alla riga 4 tramite la funzione iniettata [$session];
15.8. I plugin dei livelli [dao]

15.8.1. Il plugin del livello [dao] del client [nuxt]
Lo script [client/plgDao] è il seguente:
/* eslint-disable no-console */
// si crea un punto di accesso al livello [Dao]
import Dao from '@/api/client/Dao'
export default (context, inject) => {
// configurazione di axios
context.$axios.defaults.timeout = context.env.timeout
context.$axios.defaults.baseURL = context.env.baseURL
context.$axios.defaults.withCredentials = context.env.withCredentials
// istanziazione del livello [dao]
const dao = new Dao(context.$axios)
// Inserimento di una funzione [$dao] nel contesto
inject('dao', () => dao)
// log
console.log('[fonction client $dao créée]')
}
- riga 3: viene importato il livello [dao] del client [nuxt];
- righe 6-8: si configura l’oggetto [context.$axios] che effettuerà le richieste HTTP del livello [dao] del client [nuxt] con le informazioni del file [nuxt.config]:
// ambiente
env: {
// configurazione di Axios
timeout: 2000,
withCredentials: true,
baseURL: 'http://localhost/php7/scripts-web/impots/version-14',
// configurazione del cookie di sessione [nuxt]
maxAge: 60 * 5
}
- riga 10: viene istanziato il livello [dao] del client [nuxt];
- riga 12: la funzione [$dao] viene inserita nel contesto e nelle pagine del cliente. Questa funzione consente di accedere al livello [dao] della riga 10;
Si noti quindi che per accedere al livello [dao] del client [nuxt] quando quest'ultimo viene eseguito, si scriverà:
- [context.app.$dao()] se il contesto è noto;
- [this.$dao()] in una pagina [Vue.js];
15.8.2. Il plugin del livello [dao] di serveur [nuxt]
Lo script [server/plgDao] è il seguente:
/* eslint-disable no-console */
// si crea un punto di accesso al livello [Dao]
import Dao from '@/api/server/Dao'
export default (context, inject) => {
// configurazione di axios
context.$axios.defaults.timeout = context.env.timeout
context.$axios.defaults.baseURL = context.env.baseURL
// si recupera il cookie di sessione
const store = context.app.$session().value.store
const phpSessionCookie = store ? store.phpSessionCookie : ''
console.log('session=', context.app.$session().value, 'phpSessionCookie=', phpSessionCookie)
// istanziazione del livello [dao]
const dao = new Dao(context.$axios, phpSessionCookie)
// iniezione di una funzione [$dao] nel contesto
inject('dao', () => dao)
// log
console.log('[fonction server $dao créée]')
}
- riga 3: viene importato il livello [dao] dal server [nuxt];
- righe 6-7: si configura l’oggetto [context.$axios] che effettuerà le richieste HTTP del livello [dao] del server [nuxt] utilizzando le informazioni contenute nel file [nuxt.config]:
// ambiente
env: {
// configurazione di Axios
timeout: 2000,
withCredentials: true,
baseURL: 'http://localhost/php7/scripts-web/impots/version-14',
// configurazione del cookie di sessione [nuxt]
maxAge: 60 * 5
}
- riga 9: si recupera lo store dell’applicazione [nuxt];
- riga 10: se lo store esiste, si recupera il cookie della sessione PHP poiché è necessario per istanziare il livello [dao] del server [nuxt];
- riga 13: si istanzia il livello [dao] del server [nuxt];
- riga 15: la funzione [$dao] viene inserita nel contesto e nelle pagine del server [nuxt]. Questa funzione consente di accedere al livello [dao] della riga 13;
Si noti quindi che per accedere al livello [dao] del server [nuxt] quando questo è in esecuzione, si scriverà:
- [context.app.$dao()] se il contesto è noto;
- [this.$dao()] in una pagina [Vue.js];
15.9. Lo store Vuex
![]()
Lo store [Vuex] memorizzerà tutti i dati che devono essere condivisi dai diversi componenti dell’applicazione [pages, client, serveur], senza che tali dati siano necessariamente reattivi.
/* eslint-disable no-console */
// stato dello store
export const state = () => ({
// sessione jSON avviata
jsonSessionStarted: false,
// utente autenticato
userAuthenticated: false,
// cookie di sessione PHP
phpSessionCookie: '',
// adminData
adminData: ''
})
// modifiche allo store
export const mutations = {
// sostituzione dello stato
replace(state, newState) {
for (const attr in newState) {
state[attr] = newState[attr]
}
},
// reset dello store
reset() {
this.commit('replace', { jsonSessionStarted: false, userAuthenticated: false, phpSessionCookie: '', adminData: '' })
}
}
// azioni dello store
export const actions = {
nuxtServerInit(store, context) {
// chi esegue questo codice?
console.log('nuxtServerInit, client=', process.client, 'serveur=', process.server, 'env=', context.env)
// inizializza sessione
initStore(store, context)
}
}
function initStore(store, context) {
// store è la sessione da inizializzare
// si recupera la sessione
const session = context.app.$session()
// la sessione è già stata inizializzata?
if (!session.value.initStoreDone) {
// si avvia un nuovo store
console.log("nuxtServerInit, initialisation d'une nouvelle session")
// si inserisce lo store nella sessione
session.value.store = store.state
// lo store è ora inizializzato
session.value.initStoreDone = true
} else {
console.log("nuxtServerInit, reprise d'un store existant")
// si aggiorna lo store con quello della sessione
store.commit('replace', session.value.store)
}
// si salva la sessione
session.save(context)
// log
console.log('initStore terminé, store=', store.state)
}
I dati memorizzati nello store sono i seguenti:
- riga 6: [jsonSessionStarted] verrà impostato su vero non appena l’inizializzazione di una sessione jSON con il server PHP sarà stata completata con successo, sia che essa sia stata effettuata dal client o dal server [nuxt]. Al termine di tale inizializzazione, il cookie di sessione con il server PHP sarà stato recuperato e inserito nella proprietà [phpSessionCookie], riga 10;
- riga 8: [userAuthenticated] verrà impostato su vero non appena l’autenticazione presso il server PHP avrà avuto esito positivo, sia che sia stata effettuata dal client o dal server [nuxt];
- riga 12: [adminData] sarà il valore [adminData] ottenuto dal server PHP una volta completata con successo l’autenticazione;
- righe 18-22: l'assegnazione [replace] consente di inizializzare le proprietà precedenti con quelle di un oggetto passato come parametro;
- righe 24-26: la mutazione [reset] ripristina i valori iniziali delle proprietà dello store;
- righe 31-37: la funzione [nuxtServerInit] delega il proprio lavoro alla funzione [initStore];
- righe 39-60: la funzione [initStore] ha due ruoli:
- se lo store non è stato inizializzato, viene inizializzato e inserito nella sessione;
- se lo store è già stato inizializzato, il suo valore viene recuperato dalla sessione [nuxt];
- riga 42: si recupera la sessione Nuxt;
- riga 44: si verifica se lo store è stato inizializzato:
- se non lo è, si inserisce lo store iniziale nella sessione (riga 48);
- poi, alla riga 50, si indica che lo store è stato inizializzato;
- righe 51-55: se lo store era stato inizializzato, lo si utilizza, alla riga 54, per inizializzare lo store con il valore contenuto nella sessione;
- riga 57: in ogni caso, la sessione viene salvata nel cookie [nuxt-session], insieme allo store in essa contenuto;
15.10. Il plugin [plgEventBus]

Questo plugin ha lo scopo di rendere accessibile un bus di eventi al client [nuxt] tramite una funzione [$eventBus] iniettata nel contesto del client [nuxt]. È inutile iniettarlo nel contesto del server [nuxt] poiché quest’ultimo non è in grado di gestire gli eventi. Tuttavia, abbiamo già visto che iniettarlo sul lato server e poi utilizzarlo non provoca alcun errore.
/* eslint-disable no-console */
// si crea un bus di eventi tra le viste
import Vue from 'vue'
export default (context, inject) => {
// il bus di eventi
const eventBus = new Vue()
// Inserimento di una funzione [$eventBus] nel contesto
inject('eventBus', () => eventBus)
// log
console.log('[fonction $eventBus créée]')
}
Abbiamo già incontrato questo plugin nel paragrafo relativo ai link. La funzione [$eventBus] sarà disponibile sul client tramite le notazioni:
- [context.app.$eventBus()] laddove il contesto è disponibile;
- [this.$eventBus()] nelle pagine [Vue.js] del client;
15.11. I componenti dell’applicazione [nuxt]

Il componente [layout] è quello degli esempi precedenti:
<!-- disposizione delle viste -->
<template>
<!-- riga -->
<div>
<b-row>
<!-- area a tre colonne -->
<b-col v-if="left" cols="3">
<slot name="left" />
</b-col>
<!-- area a nove colonne -->
<b-col v-if="right" cols="9">
<slot name="right" />
</b-col>
</b-row>
</div>
</template>
<script>
export default {
// parametri
props: {
left: {
type: Boolean
},
right: {
type: Boolean
}
}
}
</script>
Il componente [navigation] è il seguente:
<template>
<!-- menu Bootstrap a tre opzioni -->
<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. I layout dell’applicazione [nuxt]

15.12.1. [default]
Il layout [default] è quello utilizzato per l'esempio [nuxt-11] nel paragrafo "link":
<template>
<div class="container">
<b-card>
<!-- un messaggio -->
<b-alert show variant="success" align="center">
<h4>[nuxt-12] : requêtes HTTP avec axios</h4>
</b-alert>
<!-- vista corrente del routing -->
<nuxt />
<!-- messaggio di attesa -->
<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>
<!-- errore in un'operazione asincrona -->
<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
}
},
// ciclo di vita
beforeCreate() {
console.log('[default beforeCreate]')
},
created() {
console.log('[default created]')
if (process.client) {
// si sta ascoltando l'evento [loading]
this.$eventBus().$on('loading', this.mShowLoading)
// così come l'evento [errorLoadingMessage]
this.$eventBus().$on('errorLoading', this.mShowErrorLoading)
}
},
beforeMount() {
console.log('[default beforeMount]')
},
mounted() {
console.log('[default mounted]')
},
methods: {
// gestione del messaggio in attesa
mShowLoading(value) {
console.log('[default mShowLoading], showLoading=', value)
this.showLoading = value
},
// errore in un'operazione asincrona
mShowErrorLoading(value, errorLoadingMessage) {
console.log('[default mShowErrorLoading], showErrorLoading=', value, 'errorLoadingMessage=', errorLoadingMessage)
this.showErrorLoading = value
this.errorLoadingMessage = errorLoadingMessage
}
}
}
</script>
- righe 10-14: visualizzano il messaggio di attesa della fine di un'operazione asincrona del client [nuxt];
- righe 15-18: visualizzano l’eventuale messaggio di errore di un’operazione asincrona;
- riga 37: la funzione [created] della pagina [default] viene eseguita prima della funzione [mounted] delle pagine;
- riga 39: se l’esecutore è il client [nuxt], la pagina [default] si mette in ascolto degli eventi:
- [loading] che segnala l’inizio o la fine di un’attesa. Viene quindi eseguita la funzione [mShowLoading];
- [errorLoading], che segnala la necessità di visualizzare un messaggio di errore. Viene quindi eseguita la funzione [mShowErrorLoading];
- le pagine [nuxt]:
- visualizzano il messaggio di attesa emettendo l’evento [‘loading’, true] sul bus degli eventi;
- nascondono il messaggio di attesa emettendo l'evento [‘loading’, false] sul bus degli eventi;
- visualizzano un messaggio di errore emettendo l’evento [‘errorLoading’, true] sul bus degli eventi;
- nascondono il messaggio di errore inviando l'evento [‘errorLoading’, false] sul bus degli eventi;
15.12.2. [error]
Il layout [error] visualizza un messaggio di errore di sistema (non gestito dallo sviluppatore):
<!-- definizione della vista HTML -->
<template>
<!-- impaginazione -->
<Layout :left="true" :right="true">
<!-- avviso nella colonna di destra -->
<template slot="right">
<!-- messaggio su sfondo rosa -->
<b-alert show variant="danger" align="center">
<h4>L'erreur suivante s'est produite : {{ JSON.stringify(error) }}</h4>
</b-alert>
</template>
<!-- menu di navigazione nella colonna di sinistra -->
<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',
// componenti utilizzati
components: {
Layout,
Navigation
},
// proprietà [props]
props: { error: { type: Object, default: () => 'waiting ...' } },
// ciclo di vita
beforeCreate() {
// client e server
console.log('[error beforeCreate]')
},
created() {
// client e server
console.log('[error created, error=]', this.error)
},
beforeMount() {
// solo client
console.log('[error beforeMount]')
},
mounted() {
// solo client
console.log('[error mounted]')
}
}
</script>
15.13. La pagina [index] eseguita dal server [nuxt]

La pagina [index.vue] ha la particolarità di essere accessibile solo tramite il server [nuxt]. All’utente non viene presentato alcun link per accedervi tramite il client [nuxt]. Il suo codice è il seguente:
<!-- pagina principale -->
<template>
<Layout :left="true" :right="true">
<!-- navigazione -->
<Navigation slot="left" />
<!-- messaggio-->
<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',
// componenti utilizzati
components: {
Layout,
Navigation
},
// dati asincroni
async asyncData(context) {
// log
console.log('[index asyncData started]')
try {
// si avvia una sessione jSON
const dao = context.app.$dao()
const response = await dao.initSession()
// log
console.log('[index asyncData response=]', response)
// si recupera il cookie di sessione PHP per le richieste successive
const phpSessionCookie = dao.getPhpSessionCookie()
// si memorizza il cookie di sessione PHP nella sessione [nuxt]
context.store.commit('replace', { phpSessionCookie })
// Si è verificato un errore?
if (response.état !== 700) {
// l'errore si trova in response.réponse
throw new Error(response.réponse)
}
// si nota che la sessione jSON è stata avviata
context.store.commit('replace', { jsonSessionStarted: true })
// si restituisce il risultato
return { result: '[succès]' }
} catch (e) {
// log
console.log('[index asyncData error=]', e)
// si rileva che la sessione jSON non è stata avviata
context.store.commit('replace', { jsonSessionStarted: false })
// si segnala l'errore
return { result: '[échec]', showErrorLoading: true, errorLoadingMessage: e.message }
} finally {
// si salva lo store
const session = context.app.$session()
session.save(context)
// log
console.log('[index asyncData finished]')
}
},
// ciclo di vita
beforeCreate() {
console.log('[index beforeCreate]')
},
created() {
console.log('[index created]')
},
beforeMount() {
console.log('[index beforeMount]')
},
mounted() {
console.log('[index mounted]')
// solo client
if (this.showErrorLoading) {
console.log('[index mounted, showErrorLoading=true]')
this.$eventBus().$emit('errorLoading', true, this.errorLoadingMessage)
}
}
}
</script>
- riga 7: la pagina visualizza il risultato [result] di una richiesta asincrona (righe 46 e 51);
- riga 31: l’operazione asincrona consiste nell’apertura di una sessione jSON con il server di calcolo delle imposte;
- riga 25: si sa che quando la pagina viene richiesta direttamente al server [nuxt], la funzione [asyncData] viene eseguita solo dal server e non dal client [nuxt], che viene eseguito quando il browser ha ricevuto la risposta dal server [nuxt];
- riga 30: si recupera il livello [dao] nel contesto del server [nuxt];
- riga 35: se il server non aveva ancora effettuato una richiesta al server di calcolo delle imposte, riceve il suo primo cookie di sessione PHP, altrimenti l’ultimo cookie di sessione PHP che ha ricevuto (vedere il codice del livello [dao] del server [nuxt] al paragrafo «link»);
- riga 37: si memorizza questo cookie di sessione PHP nello store;
- righe 39-42: si verifica se l’operazione è andata a buon fine. In caso contrario, viene generata un’eccezione che verrà intercettata dal [catch] della riga 47;
- riga 44: si registra nello store che la sessione jSON con il server PHP è stata avviata;
- riga 46: viene restituito il risultato [result], che viene visualizzato alla riga 7;
- righe 47-54: viene gestita un’eventuale eccezione. Questa può essere di due tipi:
- l’operazione HTTP della riga 31 è fallita a causa di un errore di comunicazione tra il server [nuxt] e il server PHP;
- l’operazione HTTP della riga 31 è andata a buon fine, ma il risultato ricevuto ha segnalato un errore (righe 39-42);
- riga 51: si nota che la sessione jSON con il server PHP non è stata avviata;
- riga 53: viene restituito il risultato [result], visualizzato alla riga 7. Inoltre, si impostano le proprietà [showErrorLoading] e [errorLoadingMessage] che il client [nuxt] utilizzerà per visualizzare un messaggio di errore quando riceverà la pagina inviata dal server [nuxt] (righe 72-79);
- righe 54-60: codice eseguito in ogni caso (successo o fallimento);
- riga 56: si recupera la sessione [nuxt] nel contesto del server [nuxt];
- riga 57: la si salva;
- righe 63-68: una volta terminata la funzione [asyncData], il server [nuxt] esegue le funzioni [beforeCreate] e [create];
Nota: l’esecuzione della pagina [index] da parte del server [nuxt] può fallire, ad esempio, se il server di calcolo delle imposte non è in esecuzione al momento dell’avvio dell’applicazione [nuxt]:

In questo caso, l’unica soluzione è avviare il server di calcolo delle imposte e poi l’applicazione [nuxt] stessa, poiché il menu di navigazione non offre un’opzione per avviare una sessione jSON con il server di calcolo delle imposte;
15.14. La pagina [index] eseguita dal client [nuxt]
La pagina [index] viene eseguita dal client [nuxt] solo dopo che il server [nuxt] gliel’ha inviata. Quest’ultimo gli ha inviato le informazioni [result] ed eventualmente [showErrorLoading] e [errorLoadingMessage].
È noto che la funzione [asyncData] non verrà eseguita. Restano quindi le funzioni del ciclo di vita e in particolare la funzione [mounted]:
mounted() {
console.log('[index mounted]')
// solo client
if (this.showErrorLoading) {
console.log('[index mounted, showErrorLoading=true]')
this.$eventBus().$emit('errorLoading', true, this.errorLoadingMessage)
}
}
- il client [nuxt] integra automaticamente nelle proprietà della pagina gli elementi [result] ed eventualmente [showErrorLoading, errorLoadingMessage] che gli sono stati inviati dal server [nuxt]:
- la proprietà [result] viene visualizzata alla riga 7;
- le proprietà [showErrorLoading, errorLoadingMessage] vengono utilizzate dal metodo [mounted]: alla riga 4 viene verificata la proprietà [showErrorLoading]. Se è vera, alla riga 6 si utilizza il bus degli eventi del client [nuxt] per segnalare che c’è un messaggio di errore da visualizzare;
- l’evento [errorLoading] generato alla riga 6 viene intercettato dalla pagina [layouts/default] descritta nel paragrafo «link»;
15.15. La pagina [authentification] viene eseguita dal server [nuxt]
La pagina [authentification] ha il compito di identificare un utente presso il server di calcolo delle imposte. Il suo codice è il seguente:
<!-- pagina di autenticazione -->
<template>
<Layout :left="true" :right="true">
<!-- navigazione -->
<Navigation slot="left" />
<!-- messaggio-->
<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',
// componenti utilizzati
components: {
Layout,
Navigation
},
// dati asincroni
async asyncData(context) {
// log
console.log('[authentification asyncData started]')
if (process.client) {
// inizio attesa del client [nuxt]
context.app.$eventBus().$emit('loading', true)
// nessun errore
context.app.$eventBus().$emit('errorLoading', false)
}
try {
// autenticazione sul server
const dao = context.app.$dao()
const response = await dao.authentifierUtilisateur('admin', 'admin')
// log
console.log('[authentification asyncData response=]', response)
// risultato
const userAuthenticated = response.état === 200
// si registra se l'utente è autenticato o meno
context.store.commit('replace', { userAuthenticated })
// si salva lo store nella sessione [nuxt]
const session = context.app.$session()
session.save(context)
// errore di autenticazione?
if (!userAuthenticated) {
// l'errore si trova in response.réponse
throw new Error(response.réponse)
}
// si ottiene il risultato
return { result: '[succès]' }
} catch (e) {
// si segnala l'errore
return { result: '[échec]', showErrorLoading: true, errorLoadingMessage: e.message }
} finally {
// log
console.log('[authentification asyncData finished]')
if (process.client) {
// fine attesa del client [nuxt]
context.app.$eventBus().$emit('loading', false)
}
}
},
// ciclo di vita
beforeCreate() {
console.log('[authentification beforeCreate]')
},
created() {
console.log('[authentification created]')
},
beforeMount() {
console.log('[authentification beforeMount]')
},
mounted() {
console.log('[authentification mounted]')
// solo cliente
if (this.showErrorLoading) {
console.log('[authentification mounted, showErrorLoading=true]')
this.$eventBus().$emit('errorLoading', true, this.errorLoadingMessage)
}
}
}
</script>
- riga 7: la pagina visualizza il risultato [result] della richiesta asincrona [asyncData] delle righe 25-65;
- righe 28-33: il server non esegue queste righe destinate al client [nuxt];
- riga 36: si recupera il livello [dao] dal server [nuxt];
- riga 37: si effettua l'autenticazione presso il server di calcolo delle imposte con le credenziali di prova [admin, admin], che sono le uniche accettate dal server di calcolo delle imposte;
- riga 41: l'operazione di autenticazione ha esito positivo solo se la risposta è di stato 200;
- riga 43: si inserisce nel store la proprietà [userAuthenticated];
- righe 44-46: lo store viene salvato nella sessione [nuxt];
- righe 48-51: se l’autenticazione non è andata a buon fine, viene generata un’eccezione con il messaggio di errore inviato dal server di calcolo delle imposte;
- altrimenti, alla riga 53, si restituisce un risultato di successo che verrà visualizzato alla riga 7;
- righe 54-57: in caso di errore si impostano tre proprietà della pagina [result, showErrorLoading, errorLoadingMessage]. La proprietà [result] verrà visualizzata alla riga 7. Le tre proprietà saranno inviate al client [nuxt];
- righe 60-63: non vengono eseguite dal server [nuxt];
- una volta che [asyncData] ha restituito il risultato, questo viene visualizzato alla riga 7. Successivamente vengono eseguiti i metodi [beforeCreate] (righe 67-69) e [created] (righe 70-72);
- il processo è terminato;
Nota: l’esecuzione della pagina [authentification] da parte del server [nuxt] potrebbe non andare a buon fine, ad esempio se la sessione jSON con il server di calcolo delle imposte non è stata inizializzata. È possibile farlo nel modo seguente:
- eliminare il cookie di sessione PHP dal proprio browser (per ricominciare da zero):

- avviare l’applicazione [nuxt] mentre il server di calcolo non è stato avviato: si otterrà un errore;
- avviare il server di calcolo delle imposte;
- digitare URL [/authentification] direttamente nella barra degli indirizzi del browser:

In questo caso, l’unica soluzione è ricaricare nuovamente la pagina [index].
15.16. La pagina [authentification] eseguita dal client [nuxt]
Riprendiamo il codice della pagina:
<!-- pagina di autenticazione -->
<template>
<Layout :left="true" :right="true">
<!-- navigazione -->
<Navigation slot="left" />
<!-- messaggio-->
<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',
// componenti utilizzati
components: {
Layout,
Navigation
},
// dati asincroni
async asyncData(context) {
// log
console.log('[authentification asyncData started]')
if (process.client) {
// inizio attesa del client [nuxt]
context.app.$eventBus().$emit('loading', true)
// nessun errore
context.app.$eventBus().$emit('errorLoading', false)
}
try {
// autenticazione sul server
const dao = context.app.$dao()
const response = await dao.authentifierUtilisateur('admin', 'admin')
// log
console.log('[authentification asyncData response=]', response)
// risultato
const userAuthenticated = response.état === 200
// si registra se l'utente è autenticato o meno
context.store.commit('replace', { userAuthenticated })
// si salva lo store nella sessione [nuxt]
const session = context.app.$session()
session.save(context)
// errore di autenticazione?
if (!userAuthenticated) {
// l'errore si trova in response.réponse
throw new Error(response.réponse)
}
// viene restituito il risultato
return { result: '[succès]' }
} catch (e) {
// si segnala l'errore
return { result: '[échec]', showErrorLoading: true, errorLoadingMessage: e.message }
} finally {
// log
console.log('[authentification asyncData finished]')
if (process.client) {
// fine attesa del client [nuxt]
context.app.$eventBus().$emit('loading', false)
}
}
},
// ciclo di vita
beforeCreate() {
console.log('[authentification beforeCreate]')
},
created() {
console.log('[authentification created]')
},
beforeMount() {
console.log('[authentification beforeMount]')
},
mounted() {
console.log('[authentification mounted]')
// solo cliente
if (this.showErrorLoading) {
console.log('[authentification mounted, showErrorLoading=true]')
this.$eventBus().$emit('errorLoading', true, this.errorLoadingMessage)
}
}
}
</script>
Esistono due casi di esecuzione della pagina [authentification] da parte del client [nuxt]:
- il client [nuxt] viene eseguito dopo che il server [nuxt] ha inviato al browser del client [nuxt] la pagina [authentification];
- il client [nuxt] perché l’utente ha cliccato sul link [Authentification] nel menu di navigazione:

Esaminiamo innanzitutto il primo caso. In questo caso, il client [nuxt] non esegue la funzione [asyncData]. Inserisce nelle proprietà della pagina gli elementi [result] ed eventualmente [showErrorLoading, errorLoadingMessage] che gli sono stati inviati dal server [nuxt]:
- la proprietà [result] viene visualizzata alla riga 7;
- le proprietà [showErrorLoading, errorLoadingMessage] vengono utilizzate dal metodo [mounted]: alla riga 79 viene verificata la proprietà [showErrorLoading]. Se è vera, alla riga 81 si utilizza il bus degli eventi del client [nuxt] per segnalare che c’è un messaggio di errore da visualizzare;
Il meccanismo di visualizzazione del messaggio di errore è stato spiegato per la pagina [index] nel paragrafo relativo al link.
Il caso 2 riguarda il client [nuxt], eseguito quando l’utente fa clic sul link [Authentification]. In questo caso, il client [nuxt] viene eseguito in modo autonomo e non dopo il server [nuxt]. Viene quindi eseguita la funzione [asyncData]. Forniamo solo i dettagli che differiscono dalle spiegazioni fornite per la pagina eseguita dal server [nuxt]:
- righe 28-33: il client [nuxt] richiede la visualizzazione del messaggio di attesa e la rimozione di un eventuale messaggio di errore che sarebbe stato visualizzato in precedenza;
- riga 36: ora viene recuperato il livello [dao] del client [nuxt];
- righe 60-63: il client [nuxt] richiede la fine della visualizzazione del messaggio di attesa;
- una volta terminata [asyncData], avrà inizio il ciclo di vita della pagina. Verrà eseguita la funzione [mounted] delle righe 76-83. Se si è verificato un errore, verrà visualizzato il messaggio di errore;
Nota: per provocare un errore, seguire la procedura illustrata per il server [nuxt] alla fine del paragrafo «link», ma invece di richiedere la pagina [authentification] digitando il suo URL URL nella barra degli indirizzi, utilizzate il link [Authentification] dal menu di navigazione. In questo modo verrà eseguito il client [nuxt].
15.17. La pagina [get-admindata]
Il codice della pagina [get-admindata] è il seguente:
<!-- vista get-admindata -->
<template>
<Layout :left="true" :right="true">
<!-- navigazione -->
<Navigation slot="left" />
<!-- messaggio -->
<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',
// componenti utilizzati
components: {
Layout,
Navigation
},
// dati asincroni
async asyncData(context) {
// log
console.log('[get-admindata asyncData started]')
if (process.client) {
// inizio attesa
context.app.$eventBus().$emit('loading', true)
// nessun errore
context.app.$eventBus().$emit('errorLoading', false)
}
try {
// richiesta del dato [admindata]
const response = await context.app.$dao().getAdminData()
// log
console.log('[get-admindata asyncData response=]', response)
// risultato
const adminData = response.état === 1000 ? response.réponse : ''
// si inseriscono i dati nello store
context.store.commit('replace', { adminData })
// si salva lo store nella sessione [nuxt]
const session = context.app.$session()
session.save(context)
// si è verificato un errore?
if (!adminData) {
// l'errore si trova in response.réponse
throw new Error(response.réponse)
}
// si restituisce il valore ricevuto
return { result: adminData }
} catch (e) {
// si segnala l'errore
return { result: '[échec]', showErrorLoading: true, errorLoadingMessage: e.message }
} finally {
// log
console.log('[get-admindata asyncData finished]')
if (process.client) {
// fine attesa
context.app.$eventBus().$emit('loading', false)
}
}
},
// ciclo di vita
beforeCreate() {
console.log('[get-admindata beforeCreate]')
},
created() {
console.log('[get-admindata created]')
},
beforeMount() {
console.log('[get-admindata beforeMount]')
},
mounted() {
console.log('[get-admindata mounted]')
// cliente
if (this.showErrorLoading) {
console.log('[get-admindata mounted, showErrorLoading=true]')
this.$eventBus().$emit('errorLoading', true, this.errorLoadingMessage)
}
}
}
</script>
Questa pagina è molto simile alla pagina [authentification]. Le spiegazioni sono analoghe sia per la sua esecuzione da parte del server [nuxt] sia per la sua esecuzione da parte del client [nuxt]. Si noti tuttavia che la riga 7 non visualizza «successo» o «fallimento» come in precedenza, ma il valore dei dati ricevuti dal server di calcolo delle imposte (riga 52):

Il risultato sopra riportato si ottiene sia con il server che con il client [nuxt]. Per generare un errore, richiedete la pagina [get-admindata], tramite il server o il client [nuxt], senza essere autenticati:

15.18. La pagina [fin-session]
Il codice della pagina è il seguente:
<!-- pagina principale -->
<template>
<Layout :left="true" :right="true">
<!-- navigazione -->
<Navigation slot="left" />
<!-- messaggio-->
<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',
// componenti utilizzati
components: {
Layout,
Navigation
},
// dati asincroni
async asyncData(context) {
// log
console.log('[fin-session asyncData started]')
// caso del cliente [nuxt]
if (process.client) {
// inizio attesa
context.app.$eventBus().$emit('loading', true)
// nessun errore
context.app.$eventBus().$emit('errorLoading', false)
}
try {
// viene richiesta una nuova sessione PHP al server di calcolo delle imposte
const dao = context.app.$dao()
const response = await dao.finSession()
// log
console.log('[fin-session asyncData response=]', response)
// si è verificato un errore?
if (response.état !== 400) {
// l'errore si trova in response.réponse
throw new Error(response.réponse)
}
// il server ha inviato un nuovo cookie di sessione PHP
// viene recuperato sia dal server che dal client Nuxt
// se questo codice viene eseguito dal client [nuxt], il cookie di sessione PHP deve essere inserito nella sessione Nuxt
// affinché il plugin [plgDao] del server [nuxt] possa recuperarlo e inizializzare il livello [dao] con
//; se questo codice viene eseguito dal server [nuxt], il cookie di sessione PHP deve essere inserito nella sessione Nuxt
// affinché il routing del client [nuxt] lo recuperi e lo trasmetta al browser
const phpSessionCookie = dao.getPhpSessionCookie()
// si registra nello store l’avvio della sessione jSON e si memorizza il cookie di sessione PHP
context.store.commit('replace', { jsonSessionStarted: true, phpSessionCookie, userAuthenticated: false, adminData: '' })
// si salva lo store nella sessione [nuxt]
const session = context.app.$session()
session.save(context)
// si restituisce il risultato
return { result: "[succès]. La session jSON reste initialisée mais vous n'êtes plus authentifié(e)." }
} catch (e) {
// log
console.log('[fin-session asyncData error=]', e)
// si segnala l'errore
return { result: '[échec]', showErrorLoading: true, errorLoadingMessage: e.message }
} finally {
// log
console.log('[fin-session asyncData finished]')
if (process.client) {
// fine attesa
context.app.$eventBus().$emit('loading', false)
}
}
},
// ciclo di vita
beforeCreate() {
console.log('[fin-session beforeCreate]')
},
created() {
console.log('[fin-session created]')
},
beforeMount() {
console.log('[fin-session beforeMount]')
},
mounted() {
console.log('[fin-session mounted]')
// solo cliente
if (this.showErrorLoading) {
console.log('[fin-session mounted, showErrorLoading=true]')
this.$eventBus().$emit('errorLoading', true, this.errorLoadingMessage)
}
}
}
</script>
Il codice è molto simile a quello delle pagine precedenti e le spiegazioni sono le stesse. È necessario soffermarsi solo su un punto: l’operazione asincrona della riga 38 fa sì che il server di calcolo dell’imposta invii un nuovo cookie di sessione PHP. Le spiegazioni relative alla gestione di questo cookie variano a seconda che sia il server o il client [nuxt] a eseguire questo codice.
Cominciamo dal server [nuxt]:
- riga 37: viene istanziato il livello [dao] del server [nuxt]. Ricordiamo il codice del suo costruttore:
// costruttore
constructor(axios, phpSessionCookie) {
// libreria axios
this.axios = axios
// valore del cookie di sessione
this.phpSessionCookie = phpSessionCookie
// nome del cookie di sessione del server PHP
this.phpSessionCookieName = 'PHPSESSID'
}
Si nota alla riga 1 che il costruttore necessita del cookie di sessione PHP del momento, l’ultimo ricevuto, sia dal server che dal client [nuxt];
- riga 52: il server [nuxt] recupera il cookie della nuova sessione PHP oppure il cookie precedente se l’operazione di chiusura della sessione non è andata a buon fine;
- riga 54: il cookie di sessione PHP viene inserito nello store e poi salvato nella sessione [nuxt] alle righe 56-57;
- dopo il server, è il client [nuxt] che esegue la pagina [fin-session] con i dati inviati dal server. Sappiamo che non eseguirà la funzione [asyncData];
- alla fine, dopo che il server e il client [nuxt] hanno completato il loro lavoro, sappiamo che il cookie PHP necessario per gli scambi con il server di calcolo delle imposte si trova nella sessione [nuxt];
Il fatto che il cookie PHP si trovi nella sessione [nuxt] è sufficiente per il server, poiché è da lì che il suo livello [dao] lo preleverà. Nel plugin [server/plgDao] che inizializza il livello [dao] del server, è stato scritto:
/* eslint-disable no-console */
// si crea un punto di accesso al livello [Dao]
import Dao from '@/api/server/Dao'
export default (context, inject) => {
// configurazione di Axios
context.$axios.defaults.timeout = context.env.timeout
context.$axios.defaults.baseURL = context.env.baseURL
// si recupera il cookie di sessione
const store = context.app.$session().value.store
const phpSessionCookie = store ? store.phpSessionCookie : ''
console.log('session=', context.app.$session().value, 'phpSessionCookie=', phpSessionCookie)
// istanziazione del livello [dao]
const dao = new Dao(context.$axios, phpSessionCookie)
// iniezione di una funzione [$dao] nel contesto
inject('dao', () => dao)
// log
console.log('[fonction server $dao créée]')
}
- alla riga 13, il livello [dao] del server [nuxt] viene istanziato con il cookie di sessione PHP prelevato dalla sessione [nuxt], righe 9-10;
Per il client [nuxt], la situazione è diversa. Infatti non è lui a inviare il cookie, ma il browser che lo esegue. Tuttavia, questo browser non conosce il cookie della nuova sessione PHP ricevuto dal server [nuxt]. Se si utilizzano i link del menu di navigazione [3]:

Il server di calcolo delle imposte riceverà dal browser un cookie di sessione PHP obsoleto e risponderà che a tale cookie non è associata alcuna sessione jSON. Dobbiamo trovare il modo di trasmettere al browser il nuovo cookie di sessione PHP.
A tal fine è possibile utilizzare un middleware di routing:

Lo script [client/routing] è il middleware di routing dichiarato nel file [nuxt.config]:
// router
router: {
// radice dei URL dell'applicazione
base: '/nuxt-12/',
// middleware di routing
middleware: ['routing']
},
Lo script [middleware/routing] è il seguente:
/* eslint-disable no-console */
// si importa il middleware del client
import clientRouting from './client/routing'
export default function(context) {
// chi esegue questo codice?
console.log('[middleware], process.server', process.server, ', process.client=', process.client)
if (process.client) {
// routing client
clientRouting(context)
}
}
- righe 9-12: si esegue il routing solo del client con una funzione importata alla riga 4;
Lo script [middleware/client/routing] è il seguente:
/* eslint-disable no-console */
export default function(context) {
// chi esegue questo codice?
console.log('[middleware client], process.server', process.server, ', process.client=', process.client)
// gestione del cookie di sessione PHP nel browser
// il cookie di sessione PHP del browser deve essere identico a quello presente nella sessione Nuxt
// l'azione [fin-session] riceve un nuovo cookie PHP (sia dal server che dal client Nuxt)
// se è il server a riceverlo, il client deve trasmetterlo al browser
// per le proprie comunicazioni con il server PHP
//: in questo caso si tratta di un routing client
// si recupera il cookie di sessione PHP
const phpSessionCookie = context.store.state.phpSessionCookie
if (phpSessionCookie) {
// se esiste, si assegna il cookie di sessione PHP al browser
document.cookie = phpSessionCookie
}
}
Torniamo alla situazione subito dopo l’esecuzione della pagina [fin-session] da parte del server [nuxt]:

Se si clicca su uno dei link del menu [3], il client [nuxt] prenderà il controllo. Poiché si verificherà un cambio di pagina, verrà eseguito lo script di routing del client:
- riga 13: il cookie di sessione PHP viene individuato nell’archivio dell’applicazione [nuxt];
- riga 14: se non è vuoto, viene trasmesso al browser (riga 16). Da questo momento in poi, il browser del client [nuxt] dispone del cookie di sessione corretto PHP;
Lo script [client/routing] viene eseguito ad ogni cambio di pagina del client [nuxt]. Il codice dello script è valido indipendentemente dalla pagina di destinazione: semplicemente, nella maggior parte dei casi, assegna al browser un cookie di sessione PHP che esso possiede già, tranne in due casi:
- subito dopo l’avvio dell’applicazione, il server [nuxt] esegue la pagina [index] e riceve un primo cookie di sessione PHP che il browser del client [nuxt] non possiede;
- quando il server [nuxt] esegue la pagina [fin-session] come appena spiegato;
Ora esaminiamo il caso in cui la pagina [fin-session] venga eseguita esclusivamente dal client [nuxt], poiché si è cliccato sul relativo link nel menu di navigazione. Ora è il client [nuxt] che esegue la funzione [asyncData]:
try {
// si richiede una nuova sessione PHP al server di calcolo delle imposte
const dao = context.app.$dao()
const response = await dao.finSession()
// log
console.log('[fin-session asyncData response=]', response)
// si è verificato un errore?
if (response.état !== 400) {
// l'errore si trova in response.réponse
throw new Error(response.réponse)
}
// il server ha inviato un nuovo cookie di sessione PHP
// viene recuperato sia dal server che dal client Nuxt
// se questo codice viene eseguito dal client [nuxt], il cookie di sessione PHP deve essere inserito nella sessione Nuxt
// affinché il plugin [plgDao] del server [nuxt] possa recuperarlo e inizializzare il livello [dao] con
//; se questo codice viene eseguito dal server [nuxt], il cookie di sessione PHP deve essere inserito nella sessione Nuxt
// affinché il routing del client [nuxt] lo recuperi e lo trasmetta al browser
const phpSessionCookie = dao.getPhpSessionCookie()
// si registra nello store l’avvio della sessione jSON e si memorizza il cookie di sessione PHP
context.store.commit('replace', { jsonSessionStarted: true, phpSessionCookie, userAuthenticated: false, adminData: '' })
// si salva lo store nella sessione [nuxt]
const session = context.app.$session()
session.save(context)
// viene restituito il risultato
return { result: "[succès]. La session jSON reste initialisée mais vous n'êtes plus authentifié(e)." }
} catch (e) {
// log
console.log('[fin-session asyncData error=]', e)
// si segnala l'errore
return { result: '[échec]', showErrorLoading: true, errorLoadingMessage: e.message }
} finally {
// log
console.log('[fin-session asyncData finished]')
if (process.client) {
// fine attesa
context.app.$eventBus().$emit('loading', false)
}
}
- riga 3: qui viene recuperato il livello [dao] del client [nuxt];
- riga 18: il cookie di sessione PHP recuperato dal livello [dao] del client [nuxt] viene memorizzato, inserito nello store (riga 20) e successivamente salvato nella sessione [nuxt] (righe 22-23);
- da questo punto in poi tutto procede correttamente, poiché sappiamo che il livello [dao] del server [nuxt] recupererà il cookie di sessione PHP dalla sessione [nuxt];
15.19. Exécution
Per eseguire questo esempio, è necessario assicurarsi, prima dell’esecuzione, di eliminare il cookie di sessione [nuxt] e il cookie PHP dal browser che esegue il client [nuxt], in modo da partire da una situazione pulita. Di seguito un esempio con il browser Chrome:

15.20. Conclusion
Questo esempio si è rivelato particolarmente complesso. Ha richiesto l’applicazione delle conoscenze acquisite negli esempi precedenti: persistenza dello store in una sessione [nuxt], plugin per l’iniezione di funzioni, middleware di routing, gestione degli errori nelle operazioni asincrone. La complessità è stata accentuata dal fatto che volevamo che l’utente potesse utilizzare sia i link del menu di navigazione sia digitare manualmente gli URL senza che ciò causasse il malfunzionamento dell’applicazione. Per questo motivo, siamo stati costretti ad analizzare il comportamento di ciascuna pagina a seconda che venisse eseguita dal client o dal server [nuxt].
Questa uniformità di comportamento tra client e server [nuxt] non è indispensabile. Si può infatti considerare il caso frequente in cui:
- la prima pagina viene fornita dal server [nuxt];
- tutte le pagine successive vengono fornite dal client [nuxt], che opera quindi in modalità [SPA];
Tuttavia, anche in questo caso, è necessario verificare il risultato dell’esecuzione di tutte le pagine da parte del server [nuxt], poiché è proprio questo il risultato che otterranno i motori di ricerca che le richiederanno.