15. Ejemplo [nuxt-12]: solicitudes HTTP con axios
15.1. Présentation
En este nuevo ejemplo, vamos a descubrir cómo, en las funciones [asyncData], se pueden realizar peticiones HTTP con la biblioteca [axios]. Además, vamos a utilizar conceptos ya adquiridos:
- el uso de plugins del ejemplo [nuxt-06]:
- la persistencia del almacén en una cookie de sesión del ejemplo [nuxt-06];
- el control de la navegación con middlewares del ejemplo [nuxt-09];
- la gestión de errores del ejemplo [nuxt-11];
La arquitectura del ejemplo será la siguiente:

- la aplicación [nuxt] se almacenará en el servidor [node.js] [3], se descargará mediante el navegador [1], que posteriormente la ejecutará;
- tanto el cliente [nuxt] [1] como el servidor [nuxt] [3] realizarán consultas HTTP al servidor de datos [2]. Este servidor será el servidor de cálculo de impuestos desarrollado en la sección PHP 7. Utilizaremos su última versión, la versión 14, con las consultas CORS autorizadas;
La arquitectura del ejemplo se puede simplificar de la siguiente manera:

- en [1], el servidor [node.js] envía las páginas [nuxt] al navegador [2]. Es la capa [web] [8] del servidor la que entrega estas páginas. Para entregar la página, el servidor pudo haber solicitado datos externos al servidor de datos [3]. Es la capa [DAO] [9] la que realiza las solicitudes HTTP necesarias;
- cada vez que se solicita una página al servidor [node.js][1], el navegador [2] recibe la aplicación completa [nuxt], que a continuación se ejecutará en modo SPA. El bloque [UI] (interfaz de usuario) [4] muestra las páginas [vue.js] al usuario. Las acciones de este bloque o el ciclo de vida natural de las páginas pueden provocar llamadas de datos externos al servidor de datos [3]. Es la capa [DAO] [5] la que realiza entonces las consultas HTTP necesarias;
15.2. Estructura del proyecto

15.3. El archivo de configuración [nuxt.config.js]
El proyecto se controlará mediante el siguiente archivo [nuxt.config.js]:
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) { }
},
// directorio del código fuente
srcDir: 'nuxt-12',
// enrutador
router: {
// raíz de los URL de la aplicación
base: '/nuxt-12/',
// middleware de enrutamiento
middleware: ['routing']
},
// servidor
server: {
// puerto de servicio, 3000 por defecto
port: 81,
// direcciones de red a las que se escucha, por defecto localhost: 127.0.0.1
// 0.0.0.0 = todas las direcciones de red del equipo
host: 'localhost'
},
// entorno
env: {
// configuración de Axios
timeout: 2000,
withCredentials: true,
baseURL: 'http://«localhost/php7/scripts-web/impots/version-14»,
// configuración de la cookie de sesión [nuxt]
maxAge: 60 * 5
}
}
- línea 22: gestionamos nosotros mismos la alerta de espera hasta que finalice una acción asíncrona;
- línea 31: vamos a utilizar varios complementos que estarán especializados bien para el cliente, bien para el servidor, pero no para ambos a la vez;
- línea 52: el módulo [axios] está integrado en [nuxt]. Esto tendrá como consecuencia que el objeto [axios], que realizará las solicitudes HTTP de laaplicación [nuxt] al servidor PHP de cálculo de impuestos, estará disponible en [context.$axios];
- línea 54: el módulo [cookie-universal-nuxt] nos permitirá guardar la sesión [nuxt] en una cookie;
- línea 60: la propiedad [axios] nos permite configurar el módulo [@nuxtjs/axios] de la línea 52. No utilizaremos esta opción, ya que preferiremos la propiedad [env] de la línea 88;
- línea 90: tiempo máximo de espera para la respuesta del servidor de cálculo de impuestos;
- línea 91: necesaria para el cliente [nuxt]; autoriza el uso de cookies en las comunicaciones con el servidor de cálculo de impuestos;
- línea 92: el URL básico del servidor de cálculo de impuestos;
- línea 94: duración de la sesión de Nuxt (5 min);
- línea 77: la navegación entre el cliente y el servidor [nuxt] estará controlada por un middleware de enrutamiento;
15.4. La capa [UI] de la aplicación

Vamos a dar a la aplicación [nuxt] acceso al API del servidor de cálculo de impuestos a través de la siguiente vista:

- en [2], el menú que da acceso a API del servidor de cálculo de impuestos:
- [Authentification]: corresponde a la página [authentification]. Esta página realiza una solicitud de autenticación al servidor de cálculo de impuestos con las credenciales [admin, admin], que por el momento son las únicas autorizadas. El resultado que se muestra es similar al de [3];
- [Requête AdminData]: corresponde a la página [get-admindata]. Esta página solicita al servidor de cálculo de impuestos los datos, denominados aquí [adminData], que permiten calcular el impuesto. El resultado que se muestra es similar al de [3];
- [Fin session impôt]: corresponde a la página [fin-session]. Esta página envía una solicitud de fin de sesión PHP al servidor de cálculo de impuestos. A continuación, el servidor cancela la sesión actual PHP e inicia una nueva en blanco;
15.5. Las capas [dao] de la aplicación [nuxt]
Como se ha indicado anteriormente, la arquitectura de la aplicación [nuxt] será la siguiente:

- En [1], el servidor [node.js] envía las páginas [nuxt] al navegador [2]. Es la capa [web] [8] del servidor la que envía estas páginas. Para entregar la página, el servidor pudo haber solicitado datos externos al servidor de datos [3]. Es la capa [DAO] [9] la que realiza las solicitudes HTTP necesarias;
- cada vez que se solicita una página al servidor [node.js][1], el navegador [2] recibe la aplicación completa [nuxt], que a continuación se ejecutará en modo SPA. El bloque [UI] (interfaz de usuario) [4] muestra las páginas [vue.js] al usuario. Las acciones de este bloque o el ciclo de vida de las páginas pueden provocar llamadas a datos externos al servidor de datos [3]. Es la capa [DAO] [5] la que realiza entonces las consultas HTTP necesarias;
Utilizaremos la versión 14 del servidor de cálculo de impuestos desarrollado en el documento |Introducción al lenguaje PHP7 a través de un ejemplo|. Utilizaremos solo una parte de su API (Interfaz de programación de aplicaciones) jSON:
Consulta | Respuesta |
| |
| |
| |
| |
15.5.1. La capa [dao] del servidor [nuxt]

El servidor [node.js] [1] utilizará la capa [dao] descrita en el documento |Introducción al marco VUE.JS con ejemplos|. A continuación recordamos su código:
'use strict';
// importaciones
import qs from 'qs'
class Dao {
// constructor
constructor(axios) {
this.axios = axios;
// cookie de sesión
this.sessionCookieName = "PHPSESSID";
this.sessionCookie = '';
}
// inicialización de sesión
async initSession() {
// opciones de la solicitud HHTP [get /main.php?action=init-session&type=json]
const options = {
method: "GET",
// parámetros de la consulta URL
params: {
action: 'init-session',
type: 'json'
}
};
// ejecución de la consulta HTTP
return await this.getRemoteData(options);
}
async authentifierUtilisateur(user, password) {
// opciones de la solicitud HHTP [post /main.php?action=authentifier-utilisateur]
const options = {
method: "POST",
headers: {
'«Content-type»: «application/x-www-form-urlencoded»,
},
// cuerpo del POST
data: qs.stringify({
user: user,
password: password
}),
// parámetros de la URL
params: {
action: 'authentifier-utilisateur'
}
};
// ejecución de la consulta HTTP
return await this.getRemoteData(options);
}
async getAdminData() {
// opciones de la consulta HHTP [get /main.php?action=get-admindata]
const options = {
method: "GET",
// parámetros de la consulta URL
params: {
action: 'get-admindata'
}
};
// ejecución de la consulta HTTP
const data = await this.getRemoteData(options);
// resultado
return data;
}
async getRemoteData(options) {
// para la cookie de sesión
if (!options.headers) {
options.headers = {};
}
options.headers.Cookie = this.sessionCookie;
// ejecución de la consulta HTTP
let response;
try {
// solicitud asíncrona
response = await this.axios.request('main.php', options);
} catch (error) {
// el parámetro [error] es una instancia de excepción; puede adoptar diversas formas
if (error.response) {
// la respuesta del servidor se encuentra en [error.response]
response = error.response;
} else {
// se vuelve a generar el error
throw error;
}
}
//: la respuesta es el conjunto completo de la respuesta HTTP del servidor (encabezados HTTP + la propia respuesta)
// se recupera la cookie de sesión, si existe
const setCookie = response.headers['set-cookie'];
if (setCookie) {
// setCookie es una matriz
//: se busca la cookie de sesión en este array
let trouvé = false;
let i = 0;
while (!trouvé && i < setCookie.length) {
// se busca la cookie de sesión
const results = RegExp('^(' + this.sessionCookieName + '.+?);').exec(setCookie[i]);
if (results) {
// se almacena la cookie de sesión
// eslint-disable-next-line require-atomic-updates
this.sessionCookie = results[1];
// la hemos encontrado
trouvé = true;
} else {
// elemento siguiente
i++;
}
}
}
// la respuesta del servidor está en [response.data]
return response.data;
}
}
// exportación de la clase
export default Dao;
- Todos los métodos de la capa [dao] devuelven el objeto enviado por el servidor de datos [{action : ‘xx’, état : nn, réponse : {...}] con:
- [action]: el nombre de la acción ejecutada por el servidor de datos;
- [état]: indicador numérico:
- [initSession]: estado=700 para una respuesta sin errores;
- [authentifierUtilisateur]: estado=200 para una respuesta sin errores;
- [getAdminData]: estado=1000 para una respuesta sin errores;
- [fin-session]: estado=400 para una respuesta sin errores;
- [réponse]: respuesta asociada al indicador numérico [état]. Puede variar en función de dicho indicador numérico;
Analicemos el constructor de la clase [Dao]:
// constructor
constructor(axios) {
this.axios = axios;
// cookie de sesión
this.sessionCookieName = "PHPSESSID";
this.sessionCookie = '';
}
- línea 2: el objeto [axios], proporcionado como argumento al constructor, lo proporciona el código que realiza la llamada. Es este el que realizará las solicitudes HTTP;
- línea 5: el nombre de la cookie de sesión enviada por el servidor de datos, escrito como PHP;
- línea 6: la cookie de sesión que se intercambia entre la capa [dao] y el servidor de datos. Esta se inicializa mediante la función [getRemoteData] de las líneas 67-113;
En cuanto a la cookie de sesión, debemos tener en cuenta dos capas [dao] distintas:
- la del navegador;
- la del servidor;
Tendremos que gestionar tres cookies de sesión:
- la que se intercambia entre el cliente [nuxt] y el servidor PHP 7;
- la que se intercambia entre el servidor [nuxt] y el servidor PHP 7;
- la que se intercambia entre el cliente [nuxt] y el servidor [nuxt];
Nos aseguraremos de que la cookie de sesión con el servidor PHP sea la misma tanto para el cliente como para el servidor [nuxt]. A esta cookie la llamaremos «cookie de sesión PHP». Esta es la cookie de los casos 1 y 2. A la cookie del caso 3 la llamaremos «cookie de sesión [nuxt]». Por lo tanto, tendremos dos sesiones:
- una sesión PHP con la cookie de sesión PHP;
- una sesión [nuxt] con la cookie de sesión [nuxt];
¿Por qué utilizar la misma cookie para las sesiones PHP del cliente y del navegador [nuxt]? Queremos que la aplicación pueda comunicarse con el servidor PHP tanto con el cliente como con el servidor [nuxt]:
- si una acción A del servidor [nuxt] pone al servidor PHP en un estado E, dicho estado se refleja en la sesión PHP mantenida por el servidor PHP;
- al utilizar la misma cookie de sesión PHP que el servidor, una acción B del cliente [nuxt] que siguiera a la acción A del servidor [nuxt] encontraría al servidor PHP en elestado E dejado por el servidor [nuxt] y, por lo tanto, podría basarse en el trabajo ya realizado por el servidor [nuxt];
- si tras la acción B del cliente [nuxt] se produce una acción C del servidor [nuxt], por la misma razón que antes, esta acción podrá basarse en el trabajo realizado por la acción B del cliente [nuxt];
Para que el navegador del cliente [nuxt] pueda comunicarse con el servidor PHP de cálculo de impuestos, utilizaremos la versión 14 de este servidor, que permite las llamadas entre dominios, es decir, aquellas de un navegador al servidor PHP. Las llamadas del servidor [nuxt] al servidor PHP no son, por su parte, llamadas entre dominios. Este concepto solo existe para las llamadas realizadas desde un navegador.
Volvamos al código del constructor de la clase [Dao] anterior:
// constructor
constructor(axios) {
this.axios = axios;
// cookie de sesión
this.sessionCookieName = "PHPSESSID";
this.sessionCookie = '';
}
- las líneas 5 y 6 corresponden a la cookie de sesión PHP con el servidor de cálculo de impuestos;
La gestión de la cookie de sesión PHP anterior no es adecuada para el servidor [nuxt]: su capa [dao] se instancia con cada nueva solicitud realizada al servidor [nuxt]. Recordemos que solicitar una página al servidor [nuxt] equivale a reiniciar la aplicación [nuxt]. Así, cuando, al finalizar la primera solicitud realizada al servidor de datos por el servidor [nuxt], se inicializa la cookie de sesión PHP de la capa [dao], este valor se pierde durante la siguiente solicitud HTTP del mismo servidor [nuxt], ya que, entretanto, se ha vuelto a crear su capa [dao], se ha vuelto a ejecutar el constructor y se ha reiniciado la cookie de sesión PHP con la cadena vacía (línea 6);
Una solución consiste en utilizar otro constructor para la capa [dao] del servidor:
// constructor
constructor(axios, phpSessionCookie) {
// biblioteca axios
this.axios = axios
// valor de la cookie de sesión
this.phpSessionCookie = phpSessionCookie
// nombre de la cookie de sesión del servidor PHP
this.phpSessionCookieName = 'PHPSESSID'
}
- línea 2: en esta ocasión, la cookie de sesión PHP se proporcionará al constructor de la capa [dao] del servidor de datos;
¿Cómo podrá el servidor [nuxt] proporcionar esta cookie de sesión PHP al constructor de su capa [dao]? Almacenaremos la cookie de sesión PHP en la cookie de sesión [nuxt] intercambiada entre el navegador y el servidor [nuxt]. El proceso es el siguiente:
- se inicia la aplicación [nuxt];
- cuando el servidor [nuxt] realiza su primera solicitud HTTP al servidor PHP, almacena la cookie de sesión PHP que ha recibido en la cookie de sesión [nuxt] que intercambia con el cliente [nuxt];
- el navegador que aloja al cliente [nuxt] recibe esta cookie de sesión [nuxt] y, por lo tanto, la reenvía sistemáticamente con cada nueva solicitud al servidor [nuxt];
- cuando el servidor [nuxt] tenga que realizar una nueva solicitud al servidor PHP, encontrará la cookie de sesión PHP en la cookie de sesión [nuxt] que le habrá enviado el navegador. A continuación, la enviará al servidor PHP;
Hay dos cookies de sesión y no hay que confundirlas:
- la cookie de sesión [nuxt] intercambiada entre el servidor [nuxt] y el navegador del cliente [nuxt];
- la cookie de sesión PHP, intercambiada entre el servidor [nuxt] y el servidor PHP, o entre el cliente [nuxt] y el servidor PHP;
Volvamos ahora al código del método de la clase [Dao]. No incluye ninguna función para cerrar la sesión PHP con el servidor de cálculo de impuestos. Añadimos la siguiente:
// fin de la sesión de cálculo de impuestos
async finSession() {
// opciones de la solicitud HHTP [get /main.php?action=fin-session]
const options = {
method: 'GET',
// parámetros de la consulta URL
params: {
action: 'fin-session'
}
}
// ejecución de la consulta HTTP
const data = await this.getRemoteData(options)
// resultado
return data
}
Al realizar las pruebas, descubrimos que la función [getRemoteData], llamada en la línea 12, no es adecuada para el método [finSession]:
async getRemoteData(options) {
// para la cookie de sesión
if (!options.headers) {
options.headers = {};
}
options.headers.Cookie = this.sessionCookie;
// ejecución de la consulta HTTP
let response;
try {
// solicitud asíncrona
response = await this.axios.request('main.php', options);
} catch (error) {
// el parámetro [error] es una instancia de excepción; puede adoptar diversas formas
if (error.response) {
// la respuesta del servidor se encuentra en [error.response]
response = error.response;
} else {
// Se vuelve a generar el error
throw error;
}
}
// la respuesta es el conjunto completo de la respuesta HTTP del servidor (encabezados HTTP + la propia respuesta)
// se recupera la cookie de sesión, si existe
const setCookie = response.headers['set-cookie'];
if (setCookie) {
// setCookie es una matriz
//: se busca la cookie de sesión en este array
let trouvé = false;
let i = 0;
while (!trouvé && i < setCookie.length) {
// se busca la cookie de sesión
const results = RegExp('^(' + this.sessionCookieName + '.+?);').exec(setCookie[i]);
if (results) {
// se almacena la cookie de sesión
// eslint-disable-next-line require-atomic-updates
this.sessionCookie = results[1];
// la hemos encontrado
trouvé = true;
} else {
// el siguiente elemento
i++;
}
}
}
// la respuesta del servidor está en [response.data]
return response.data;
}
- líneas 30-43: se busca la cookie [PHPSESSID=xxx]. Si se encuentra, se almacena en la clase (línea 36);
Este código no es válido para el nuevo método [finSession], ya que en la acción [fin-session], el servidor PHP envía dos cookies con el nombre [PHPSESSID]. A continuación se muestra un ejemplo obtenido con un cliente [Postman]:

- en [1], la solicitud del cliente [Postman];
- en [3], la respuesta del servidor PHP;
- en [4], los encabezados HTTP de la respuesta del servidor PHP;

- en [5], el servidor PHP indica primero que ha eliminado la sesión actual PHP;
- En [6], el servidor PHP envía la cookie de la nueva sesión PHP;
Con el código actual, la función [getRemoteData] recupera la cookie [5], cuando lo que hay que memorizar es la cookie [6].
Por lo tanto, hay que modificar el código de la función [getRemoteData]:
async getRemoteData(options) {
// ¿Hay una cookie de sesión PHP?
if (this.phpSessionCookie) {
// ¿Hay encabezados?
if (!options.headers) {
// Se crea un objeto vacío
options.headers = {}
}
// encabezado de la cookie de sesión PHP
options.headers.Cookie = this.phpSessionCookie
}
// ejecución de la solicitud HTTP
let response
try {
// solicitud asíncrona
response = await this.axios.request('main.php', options)
} catch (error) {
// el parámetro [error] es una instancia de excepción; puede adoptar diversas formas
if (error.response) {
// la respuesta del servidor se encuentra en [error.response]
response = error.response
} else {
// se vuelve a generar el error
throw error
}
}
//: la respuesta es el conjunto completo de la respuesta HTTP del servidor (encabezados HTTP + la propia respuesta)
// se busca la cookie de sesión PHP entre las cookies recibidas
// todas las cookies recibidas
const cookies = response.headers['set-cookie']
if (cookies) {
// las cookies son una matriz
// se busca la cookie de sesión PHP en este array
let trouvé = false
let i = 0
while (!trouvé && i < cookies.length) {
// se busca la cookie de sesión PHP
const results = RegExp('^(' + this.phpSessionCookieName + '.+?)$').exec(cookies[i])
if (results) {
// se almacena la cookie de sesión PHP
const phpSessionCookie = results[1]
// ¿Contiene la palabra [deleted]?
const results2 = RegExp(this.phpSessionCookieName + '=deleted').exec(phpSessionCookie)
if (!results2) {
// tenemos la cookie de sesión correcta PHP
this.phpSessionCookie = phpSessionCookie
// Se ha encontrado
trouvé = true
} else {
// el siguiente elemento
i++
}
} else {
// elemento siguiente
i++
}
}
}
// la respuesta del servidor está en [response.data]
return response.data
}
- línea 41: se ha encontrado una cookie con el nombre [PHPSESSID]. Se almacena localmente;
- línea 43: se comprueba si en la cookie guardada aparece la cadena [PHPSESSID=deleted];
- línea 46: si la respuesta es no, significa que se ha encontrado la cookie correcta, [PHPSESSID]. Se almacena en la clase;
Tras la función [getRemoteData], la cookie de sesión PHP se almacena en la clase, en [this.phpSessionCookie]. Se ha dicho que la clase se instancia con cada nueva solicitud HTTP del servidor [nuxt]. Por lo tanto, la cookie de sesión PHP debe extraerse de la clase. Para ello, se añade un nuevo método a la misma:
// acceso a la cookie de sesión PHP
getPhpSessionCookie() {
return this.phpSessionCookie
}
- el servidor [nuxt] solicita una acción a su capa [dao] proporcionando la cookie de sesión PHP a su constructor, si lo tiene;
- una vez realizada la acción, el servidor [nuxt] recupera la cookie de sesión PHP almacenada por la capa [dao] mediante el método [getPhpSessionCookie] anterior. Esta cookie puede ser la misma que la anterior o otra diferente. Este último caso se da en dos ocasiones:
- al ejecutarse el método [initSession] (antes no existía ninguna cookie de sesión PHP);
- al ejecutarse el método [finSession] (el servidor PHP cambia la cookie de sesión PHP);
Cabe destacar una particularidad de la cookie de sesión PHP. El servidor [nuxt] no siempre recibe esta cookie del servidor PHP. De hecho, este último solo la envía una vez. A partir de entonces, ya no la envía. Si observamos el código de [getRemoteData] y el de [getPhpSessionCookie], veremos que, cuando el servidor PHP no envía ninguna cookie de sesión, la función [getPhpSessionCookie] devuelve la cookie de sesión PHP proporcionada al constructor. De este modo, el servidor siempre envía al servidor PHP la última cookie de sesión PHP que este le ha enviado.
15.5.2. La capa [dao] del cliente [nuxt]

Para el cliente [nuxt] que se ejecuta en un navegador, retomamos el código de la clase [Dao] del documento |Introducción al framework VUE.JS con un ejemplo|:
"use strict";
// importaciones
import qs from "qs";
class Dao {
// constructor
constructor(axios) {
this.axios = axios;
}
// inicialización de sesión
async initSession() {
// opciones de la solicitud HHTP [get /main.php?action=init-session&type=json]
const options = {
method: "GET",
// parámetros de la consulta URL
params: {
action: "init-session",
type: "json"
}
};
// ejecución de la consulta HTTP
return await this.getRemoteData(options);
}
async authentifierUtilisateur(user, password) {
// opciones de la consulta HHTP [post /main.php?action=authentifier-utilisateur]
const options = {
method: "POST",
headers: {
"Content-type": "application/x-www-form-urlencoded"
},
// cuerpo de POST
data: qs.stringify({
user: user,
password: password
}),
// parámetros de la URL
params: {
action: "authentifier-utilisateur"
}
};
// ejecución de la consulta HTTP
return await this.getRemoteData(options);
}
async getAdminData() {
// opciones de la consulta HHTP [get /main.php?action=get-admindata]
const options = {
method: "GET",
// parámetros de la consulta URL
params: {
action: "get-admindata"
}
};
// ejecución de la consulta HTTP
const data = await this.getRemoteData(options);
// resultado
return data;
}
async getRemoteData(options) {
// ejecución de la consulta HTTP
let response;
try {
// consulta asíncrona
response = await this.axios.request("main.php", options);
} catch (error) {
// el parámetro [error] es una instancia de excepción; puede adoptar diversas formas
if (error.response) {
// la respuesta del servidor se encuentra en [error.response]
response = error.response;
} else {
// Se vuelve a generar el error
throw error;
}
}
// la respuesta es el conjunto completo de la respuesta HTTP del servidor (encabezados HTTP + la propia respuesta)
// la respuesta del servidor se encuentra en [response.data]
return response.data;
}
}
// exportación de la clase
export default Dao;
Este código se diferencia de la capa [dao] del servidor [nuxt] en que no gestiona la cookie de sesión PHP con el servidor de cálculo de impuestos: es el navegador el que se encarga de ello.
Al igual que hicimos con la capa [dao] del servidor [nuxt], vamos a añadir un método [finSession]:
// fin de la sesión de cálculo del impuesto
async finSession() {
// opciones de la consulta HHTP [get /main.php?action=fin-session]
const options = {
method: 'GET',
// parámetros de la consulta URL
params: {
action: 'fin-session'
}
}
// ejecución de la consulta HTTP
const data = await this.getRemoteData(options)
// resultado
return data
}
Cuando el cliente [nuxt] ejecuta este método, recibe, al igual que el servidor [nuxt], dos cookies de sesión PHP. En realidad, es el navegador el que las recibe y gestiona correctamente la situación: solo conserva la cookie de la nueva sesión PHP que ha iniciado el servidor de cálculo de impuestos. Por lo tanto, en la siguiente acción del cliente [nuxt] hacia el servidor PHP, la cookie de sesión PHP será correcta, ya que es el navegador quien la envía. Sin embargo, hay un problema: el servidor [nuxt] no tiene constancia de que la cookie de sesión PHP haya cambiado. Por lo tanto, en sus comunicaciones con el servidor PHP, enviará una cookie de sesión PHP que ya no existe, lo que provocará problemas. El cliente [nuxt] debería notificar al servidor [nuxt] que la cookie de sesión PHP ha cambiado y transmitirle esta última. Sabemos cómo puede hacerlo: a través de la cookie de sesión [nuxt], la cookie intercambiada entre el cliente y el servidor [nuxt]. El cliente [nuxt] tiene al menos dos formas de recuperar la nueva cookie de sesión PHP:
- solicitándola al navegador;
- utilizando el método [getRemoteData] del servidor, que sabe cómo recuperar la nueva cookie de sesión PHP;
Vamos a utilizar la segunda solución, ya que está lista para usar. El método [getRemoteData] del cliente [nuxt] queda entonces así:
async getRemoteData(options) {
// ejecución de la consulta HTTP
let response
try {
// consulta asíncrona
response = await this.axios.request('main.php', options)
} catch (error) {
// el parámetro [error] es una instancia de excepción; puede adoptar diversas formas
if (error.response) {
// la respuesta del servidor se encuentra en [error.response]
response = error.response
} else {
// Se vuelve a generar el error
throw error
}
}
//: la respuesta es el conjunto completo de la respuesta HTTP del servidor (encabezados HTTP + la propia respuesta)
// se busca la cookie de sesión PHP entre las cookies recibidas
// todas las cookies recibidas
const cookies = response.headers['set-cookie']
if (cookies) {
// las cookies son una matriz
// se busca la cookie de sesión PHP en este array
let trouvé = false
let i = 0
while (!trouvé && i < cookies.length) {
// se busca la cookie de sesión PHP
const results = RegExp('^(' + this.phpSessionCookieName + '.+?)$').exec(cookies[i])
if (results) {
// se almacena la cookie de sesión PHP
const phpSessionCookie = results[1]
// ¿Contiene la palabra [deleted]?
const results2 = RegExp(this.phpSessionCookieName + '=deleted').exec(phpSessionCookie)
if (!results2) {
// tenemos la cookie de sesión correcta PHP
this.phpSessionCookie = phpSessionCookie
// Se ha encontrado
trouvé = true
} else {
// el siguiente elemento
i++
}
} else {
// elemento siguiente
i++
}
}
}
// la respuesta del servidor está en [response.data]
return response.data
}
En [getRemoteData] solo se ha conservado el código que procesa la respuesta del servidor PHP en busca de la cookie de sesión PHP. No se ha conservado el código que incluía la cookie de sesión PHP en la solicitud al servidor PHP, ya que es el navegador que aloja al cliente [nuxt] el que se encarga de ello.
Una vez que el cliente [nuxt] ha obtenido la cookie de sesión PHP, esta debe introducirse en la sesión [nuxt] para que el servidor [nuxt] pueda beneficiarse de ella. No es la capa [dao] la que se encarga de ello, sino que proporciona acceso, mediante un método, a la cookie de sesión PHP que ha almacenado:
// acceso a la cookie de sesión PHP
getPhpSessionCookie() {
return this.phpSessionCookie
}
La función [getPhpSessionCookie] no siempre devuelve una cookie de sesión válida:
- hay que tener en cuenta aquí que la capa [dao] del cliente [nuxt] es persistente. Se instancia una vez y permanece en memoria a partir de entonces;
- mientras el servidor PHP no envíe una cookie de sesión PHP al cliente [nuxt], la función [getPhpSessionCookie] del cliente [nuxt] devuelve el valor [undefined];
- cuando el servidor PHP envía una cookie de sesión PHP al cliente [nuxt], esta se almacena en [this.phpSessionCookie] y permanecerá allí hasta que sea sustituida por una nueva cookie de sesión PHP enviada por el servidor PHP. La función [getPhpSessionCookie] del cliente [nuxt] devuelve entonces la última cookie de sesión PHP recibida;
La capa [dao] del cliente [nuxt] solo se diferencia de la del servidor [nuxt] en un aspecto: no envía ella misma la cookie de sesión PHP, ya que es el navegador quien lo hace. No obstante, se ha preferido mantener dos capas [dao] distintas, ya que los razonamientos que conducen a sus respectivas escrituras son diferentes.
15.6. La sesión [nuxt]
![]()
La sesión [nuxt] (entre el cliente y el servidor Nuxt) se encapsulará en el siguiente objeto [session]:
/* eslint-disable no-console */
// definición de la sesión
const session = {
// contenido de la sesión
value: {
// store no inicializado
initStoreDone: false,
// valor del almacén Vuex
store: ''
},
// almacenamiento de la sesión en una cookie
save(context) {
// Almacenamiento del valor en la sesión
this.value.store = context.store.state
console.log('nuxt-session save=', this.value)
// almacenamiento del valor de la sesión
context.app.$cookies.set('nuxt-session', this.value, { path: context.base, maxAge: context.env.maxAge })
},
// reinicio de la sesión
reset(context) {
console.log('nuxt-session reset')
// restablecimiento del almacén
context.store.commit('reset')
// guardado del nuevo almacén en la sesión y guardado de la sesión
this.save(context)
}
}
// exportación de la sesión
export default session
- líneas 5-10: la sesión solo tiene una propiedad, [value], con dos subpropiedades:
- [initStoreDone], que indica si el almacén se ha inicializado o no;
- [store]: el valor [store.state] del almacén Vuex de la aplicación;
- líneas 12-18: el método [save] sirve para guardar la sesión [nuxt] en una cookie. Aquí se utiliza la biblioteca [cookie-universal-nuxt] para gestionar la cookie. Cabe destacar el nombre de la cookie de la sesión [nuxt]: [nuxt-session] (línea 17);
- líneas 20-26: el método [reset] reinicia la sesión [nuxt];
- línea 23: el almacén Vuex se reinicia y, a continuación, se guarda en la sesión, línea 25;
15.7. Los complementos de gestión de la sesión [nuxt]

15.7.1. El complemento de gestión de sesión [nuxt] de serveur [nuxt]
Al iniciar la aplicación, el servidor [nuxt] es el primero en entrar en funcionamiento. Por lo tanto, es él quien inicializará la sesión [nuxt]. El script [server/plgSession] es el siguiente:
/* eslint-disable no-console */
// importación de la sesión
import session from '@/entities/session'
export default (context, inject) => {
// gestión de la sesión del servidor
console.log('[plugin server plgSession]')
// ¿Existe ya una sesión?
const value = context.app.$cookies.get('nuxt-session')
if (!value) {
// nueva sesión
console.log("[plugin server plgSession], démarrage d'une nouvelle session")
} else {
// sesión existente
console.log("[plugin server plgSession], reprise d'une session existante")
session.value = value
}
// Se inyecta una función en [context, Vue] que convertirá la sesión en la actual
inject('session', () => session)
}
- línea 4: se importa el código de la sesión [nuxt];
- línea 11: se recupera el valor de la cookie de la sesión [nuxt];
- líneas 12-15: si la cookie de la sesión [nuxt] no existiera, entonces la sesión [nuxt] importada en la línea 4 sería suficiente. No hay nada más que hacer;
- líneas 15-19: si existiera la cookie de la sesión [nuxt], entonces, en la línea 18, se almacena su valor en la sesión importada en la línea 4;
- línea 22: la sesión se ha inicializado o se ha restaurado. Se pone a disposición mediante la función [$session];
15.7.2. El complemento de gestión de la sesión [nuxt] del cliente [nuxt]
El script [client/plgSession] es el siguiente:
/* eslint-disable no-console */
// importación de la sesión
import session from '@/entities/session'
export default (context, inject) => {
// gestión de la sesión del cliente
console.log('[plugin client plgSession], reprise de la session [nuxt] du serveur')
// se recupera la sesión existente del servidor Nuxt
session.value = context.app.$cookies.get('nuxt-session')
// se inyecta una función en [context, Vue] que establecerá la sesión como actual
inject('session', () => session)
}
- línea 4: se importa la sesión [nuxt];
- línea 10: se recupera la sesión [nuxt] actual de la cookie [nuxt-session];
- línea 13: se devuelve la sesión [nuxt] importada en la línea 4 a través de la función inyectada [$session];
15.8. Los complementos de las capas [dao]

15.8.1. El complemento de la capa [dao] del cliente [nuxt]
El script [client/plgDao] es el siguiente:
/* eslint-disable no-console */
// se crea un punto de acceso a la capa [Dao]
import Dao from '@/api/client/Dao'
export default (context, inject) => {
// configuración de Axios
context.$axios.defaults.timeout = context.env.timeout
context.$axios.defaults.baseURL = context.env.baseURL
context.$axios.defaults.withCredentials = context.env.withCredentials
// instanciación de la capa [dao]
const dao = new Dao(context.$axios)
// Inyección de una función [$dao] en el contexto
inject('dao', () => dao)
// registro
console.log('[fonction client $dao créée]')
}
- línea 3: se importa la capa [dao] del cliente [nuxt];
- líneas 6-8: se configura elobjeto [context.$axios], que realizará las consultas HTTP de la capa [dao] del cliente [nuxt] con la información del archivo [nuxt.config]:
// entorno
env: {
// configuración de Axios
timeout: 2000,
withCredentials: true,
baseURL: 'http://localhost/php7/scripts-web/impots/version-14',
// configuración de la cookie de sesión [nuxt]
maxAge: 60 * 5
}
- línea 10: se instancia la capa [dao] del cliente [nuxt];
- línea 12: la función [$dao] se inyecta en el contexto y en las páginas del cliente. Esta función da acceso a la capa [dao] de la línea 10;
Por lo tanto, hay que tener en cuenta que, para acceder a la capa [dao] del cliente [nuxt] cuando este se ejecuta, se escribirá:
- [context.app.$dao()] cuando se conoce el contexto;
- [this.$dao()] en una página [Vue.js];
15.8.2. El complemento de la capa [dao] de serveur [nuxt]
El script [server/plgDao] es el siguiente:
/* eslint-disable no-console */
// se crea un punto de acceso a la capa [Dao]
import Dao from '@/api/server/Dao'
export default (context, inject) => {
// Configuración de Axios
context.$axios.defaults.timeout = context.env.timeout
context.$axios.defaults.baseURL = context.env.baseURL
// se recupera la cookie de sesión
const store = context.app.$session().value.store
const phpSessionCookie = store ? store.phpSessionCookie : ''
console.log('session=', context.app.$session().value, 'phpSessionCookie=', phpSessionCookie)
// instanciación de la capa [dao]
const dao = new Dao(context.$axios, phpSessionCookie)
// inyección de una función [$dao] en el contexto
inject('dao', () => dao)
// registro
console.log('[fonction server $dao créée]')
}
- línea 3: se importa la capa [dao] del servidor [nuxt];
- líneas 6-7: se configura elobjeto [context.$axios], que realizará las consultas HTTP de la capa [dao] del servidor [nuxt] con la información del archivo [nuxt.config]:
// entorno
env: {
// configuración de Axios
timeout: 2000,
withCredentials: true,
baseURL: 'http://localhost/php7/scripts-web/impots/version-14',
// configuración de la cookie de sesión [nuxt]
maxAge: 60 * 5
}
- línea 9: se recupera el almacén de la aplicación [nuxt];
- línea 10: si la tienda existe, se recupera la cookie de la sesión PHP, ya que se necesita para instanciar la capa [dao] del servidor [nuxt];
- línea 13: se instancian la capa [dao] del servidor [nuxt];
- línea 15: la función [$dao] se inyecta en el contexto y en las páginas del servidor [nuxt]. Esta función da acceso a la capa [dao] de la línea 13;
Por lo tanto, hay que tener en cuenta que, para acceder a la capa [dao] del servidor [nuxt] cuando este se está ejecutando, se escribirá:
- [context.app.$dao()] cuando se conoce el contexto;
- [this.$dao()] en una página [Vue.js];
15.9. El almacén Vuex
![]()
El almacén [Vuex] almacenará todos los datos que deben compartirse entre los distintos componentes de la aplicación [pages, client, serveur], sin que por ello dichos datos sean reactivos.
/* eslint-disable no-console */
// estado de la tienda
export const state = () => ({
// sesión jSON iniciada
jsonSessionStarted: false,
// usuario autenticado
userAuthenticated: false,
// cookie de sesión PHP
phpSessionCookie: '',
// adminData
adminData: ''
})
// cambios en el almacén
export const mutations = {
// sustitución del estado
replace(state, newState) {
for (const attr in newState) {
state[attr] = newState[attr]
}
},
// reinicio del almacén
reset() {
this.commit('replace', { jsonSessionStarted: false, userAuthenticated: false, phpSessionCookie: '', adminData: '' })
}
}
// acciones del almacén
export const actions = {
nuxtServerInit(store, context) {
// ¿Quién ejecuta este código?
console.log('nuxtServerInit, client=', process.client, 'serveur=', process.server, 'env=', context.env)
// iniciar sesión
initStore(store, context)
}
}
function initStore(store, context) {
// store es la sesión que hay que inicializar
// se recupera la sesión
const session = context.app.$session()
// ¿Se ha inicializado ya la sesión?
if (!session.value.initStoreDone) {
// se inicia un nuevo almacén
console.log("nuxtServerInit, initialisation d'une nouvelle session")
// se añade el almacén a la sesión
session.value.store = store.state
// El almacén ya está inicializado
session.value.initStoreDone = true
} else {
console.log("nuxtServerInit, reprise d'un store existant")
// Se actualiza el almacén con el de la sesión
store.commit('replace', session.value.store)
}
// se guarda la sesión
session.save(context)
// registro
console.log('initStore terminé, store=', store.state)
}
Los datos almacenados en el almacén son los siguientes:
- línea 6: [jsonSessionStarted] se establecerá en «verdadero» tan pronto como se haya completado con éxito la inicialización de una sesión jSON con el servidor PHP, tanto si la ha realizado el cliente como el servidor [nuxt]. Al finalizar esta inicialización, la cookie de sesión con el servidor PHP se habrá recuperado y se habrá almacenado en la propiedad [phpSessionCookie], línea 10;
- línea 8: [userAuthenticated] se establecerá en verdadero tan pronto como se haya completado con éxito la autenticación con el servidor PHP, tanto si la ha realizado el cliente como el servidor [nuxt];
- línea 12: [adminData] será el valor [adminData] obtenido del servidor PHP una vez que la autenticación se haya realizado con éxito;
- líneas 18-22: la mutación [replace] permite inicializar las propiedades anteriores con las de un objeto pasado como parámetro;
- líneas 24-26: la mutación [reset] restablece los valores iniciales de las propiedades del almacén;
- líneas 31-37: la función [nuxtServerInit] delega su trabajo a la función [initStore];
- líneas 39-60: la función [initStore] tiene dos funciones:
- si el almacén no se ha inicializado, se inicializa y se incorpora a la sesión;
- si el almacén ya se ha inicializado, se recupera su valor de la sesión [nuxt];
- línea 42: se recupera la sesión de Nuxt;
- línea 44: se comprueba si el store se ha inicializado:
- si no es así, se introduce el valor inicial del store en la sesión (línea 48);
- luego, en la línea 50, se indica que el almacén se ha inicializado;
- líneas 51-55: si el almacén estaba inicializado, se utiliza este, en la línea 54, para inicializar el almacén con el valor contenido en la sesión;
- línea 57: en cualquier caso, la sesión se guarda en la cookie [nuxt-session], junto con el almacén que contiene;
15.10. El complemento [plgEventBus]

Este plugin tiene como objetivo hacer que un bus de eventos sea accesible para el cliente [nuxt] a través de una función [$eventBus] inyectada en el contexto del cliente [nuxt]. No tiene sentido inyectarlo en el contexto del servidor [nuxt], ya que este no sabe gestionar eventos. No obstante, ya hemos visto que inyectarlo en el lado del servidor y luego utilizarlo no provoca ningún error.
/* eslint-disable no-console */
// se crea un bus de eventos entre las vistas
import Vue from 'vue'
export default (context, inject) => {
// el bus de eventos
const eventBus = new Vue()
// inyección de una función [$eventBus] en el contexto
inject('eventBus', () => eventBus)
// registro
console.log('[fonction $eventBus créée]')
}
Ya nos hemos encontrado con este complemento en el apartado «enlace». La función [$eventBus] estará disponible en el cliente a través de las notaciones:
- [context.app.$eventBus()], cuando el contexto esté disponible;
- [this.$eventBus()] en las páginas [Vue.js] del cliente;
15.11. Los componentes de la aplicación [nuxt]

El componente [layout] es el de los ejemplos anteriores:
<!-- disposición de las vistas -->
<template>
<!-- línea -->
<div>
<b-row>
<!-- zona de tres columnas -->
<b-col v-if="left" cols="3">
<slot name="left" />
</b-col>
<!-- área de nueve columnas -->
<b-col v-if="right" cols="9">
<slot name="right" />
</b-col>
</b-row>
</div>
</template>
<script>
export default {
// parámetros
props: {
left: {
type: Boolean
},
right: {
type: Boolean
}
}
}
</script>
El componente [navigation] es el siguiente:
<template>
<!-- menú Bootstrap de tres opciones -->
<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. Los diseños de la aplicación [nuxt]

15.12.1. [default]
El diseño [default] es el que se utiliza para el ejemplo [nuxt-11] del apartado «enlace»:
<template>
<div class="container">
<b-card>
<!-- un mensaje -->
<b-alert show variant="success" align="center">
<h4>[nuxt-12] : requêtes HTTP avec axios</h4>
</b-alert>
<!-- vista actual del enrutamiento -->
<nuxt />
<!-- mensaje de espera -->
<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>
<!-- error en una operación asíncrona -->
<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 de vida
beforeCreate() {
console.log('[default beforeCreate]')
},
created() {
console.log('[default created]')
if (process.client) {
// se está escuchando el evento [loading]
this.$eventBus().$on('loading', this.mShowLoading)
// así como el evento [errorLoadingMessage]
this.$eventBus().$on('errorLoading', this.mShowErrorLoading)
}
},
beforeMount() {
console.log('[default beforeMount]')
},
mounted() {
console.log('[default mounted]')
},
methods: {
// gestión del mensaje en espera
mShowLoading(value) {
console.log('[default mShowLoading], showLoading=', value)
this.showLoading = value
},
// error en una operación asíncrona
mShowErrorLoading(value, errorLoadingMessage) {
console.log('[default mShowErrorLoading], showErrorLoading=', value, 'errorLoadingMessage=', errorLoadingMessage)
this.showErrorLoading = value
this.errorLoadingMessage = errorLoadingMessage
}
}
}
</script>
- líneas 10-14: muestran el mensaje de espera hasta que finalice una operación asíncrona del cliente [nuxt];
- líneas 15-18: muestran el posible mensaje de error de una operación asíncrona;
- línea 37: la función [created] de la página [default] se ejecuta antes que la función [mounted] de las páginas;
- línea 39: si el ejecutor es el cliente [nuxt], la página [default] se pone a la escucha de los eventos:
- [loading], que señala el inicio o el final de una espera. A continuación, se ejecuta la función [mShowLoading];
- [errorLoading], que indica que hay que mostrar un mensaje de error. A continuación, se ejecuta la función [mShowErrorLoading];
- las páginas [nuxt]:
- muestran el mensaje de espera emitiendo el evento [‘loading’, true] en el bus de eventos;
- ocultan el mensaje de espera emitiendo el evento [‘loading’, false] en el bus de eventos;
- muestran un mensaje de error emitiendo el evento [‘errorLoading’, true] en el bus de eventos;
- ocultan el mensaje de error emitiendo el evento [‘errorLoading’, false] en el bus de eventos;
15.12.2. [error]
El diseño [error] muestra un mensaje de error del sistema (no gestionado por el desarrollador):
<!-- definición HTML de la vista -->
<template>
<!-- diseño de la página -->
<Layout :left="true" :right="true">
<!-- alerta en la columna de la derecha -->
<template slot="right">
<!-- mensaje sobre fondo rosa -->
<b-alert show variant="danger" align="center">
<h4>L'erreur suivante s'est produite : {{ JSON.stringify(error) }}</h4>
</b-alert>
</template>
<!-- menú de navegación en la columna de la izquierda -->
<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',
// componentes utilizados
components: {
Layout,
Navigation
},
// propiedad [props]
props: { error: { type: Object, default: () => 'waiting ...' } },
// ciclo de vida
beforeCreate() {
// cliente y servidor
console.log('[error beforeCreate]')
},
created() {
// cliente y servidor
console.log('[error created, error=]', this.error)
},
beforeMount() {
// solo cliente
console.log('[error beforeMount]')
},
mounted() {
// solo cliente
console.log('[error mounted]')
}
}
</script>
15.13. La página [index] ejecutada por el servidor [nuxt]

La página [index.vue] tiene la particularidad de que solo se puede acceder a ella a través del servidor [nuxt]. No se muestra ningún enlace al usuario para acceder a ella a través del cliente [nuxt]. Su código es el siguiente:
<!-- página principal -->
<template>
<Layout :left="true" :right="true">
<!-- navegación -->
<Navigation slot="left" />
<!-- mensaje-->
<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',
// componentes utilizados
components: {
Layout,
Navigation
},
// datos asíncronos
async asyncData(context) {
// registro
console.log('[index asyncData started]')
try {
// se inicia una sesión jSON
const dao = context.app.$dao()
const response = await dao.initSession()
// registro
console.log('[index asyncData response=]', response)
// se recupera la cookie de sesión PHP para las próximas solicitudes
const phpSessionCookie = dao.getPhpSessionCookie()
// se almacena la cookie de sesión PHP en la sesión [nuxt]
context.store.commit('replace', { phpSessionCookie })
// ¿Se ha producido algún error?
if (response.état !== 700) {
// el error se encuentra en response.réponse
throw new Error(response.réponse)
}
// se observa que la sesión jSON se ha iniciado
context.store.commit('replace', { jsonSessionStarted: true })
// se devuelve el resultado
return { result: '[succès]' }
} catch (e) {
// registro
console.log('[index asyncData error=]', e)
// se indica que la sesión jSON no se ha iniciado
context.store.commit('replace', { jsonSessionStarted: false })
// se notifica el error
return { result: '[échec]', showErrorLoading: true, errorLoadingMessage: e.message }
} finally {
// se guarda el almacén
const session = context.app.$session()
session.save(context)
// registro
console.log('[index asyncData finished]')
}
},
// ciclo de vida
beforeCreate() {
console.log('[index beforeCreate]')
},
created() {
console.log('[index created]')
},
beforeMount() {
console.log('[index beforeMount]')
},
mounted() {
console.log('[index mounted]')
// solo para clientes
if (this.showErrorLoading) {
console.log('[index mounted, showErrorLoading=true]')
this.$eventBus().$emit('errorLoading', true, this.errorLoadingMessage)
}
}
}
</script>
- línea 7: la página muestra el resultado [result] de una consulta asíncrona (líneas 46 y 51);
- línea 31: la operación asíncrona consiste en iniciar una sesión jSON con el servidor de cálculo de impuestos;
- línea 25: sabemos que, cuando la página se solicita directamente al servidor [nuxt], la función [asyncData] solo la ejecuta el servidor y no el cliente [nuxt], que se ejecuta cuando el navegador ha recibido la respuesta del servidor [nuxt];
- línea 30: se recupera la capa [dao] en el contexto del servidor [nuxt];
- línea 35: si el servidor aún no había realizado ninguna solicitud al servidor de cálculo de impuestos, recibe su primera cookie de sesión PHP; en caso contrario, recibe la última cookie de sesión PHP que haya recibido (véase el código de la capa [dao] del servidor [nuxt] en el apartado «enlace»);
- línea 37: se almacena esta cookie de sesión PHP en el almacén;
- líneas 39-42: se comprueba si la operación se ha realizado con éxito. Si no es así, se lanza una excepción que será interceptada por el [catch] de la línea 47;
- línea 44: se anota en el almacén que se ha iniciado la sesión jSON con el servidor PHP;
- línea 46: se devuelve el resultado [result], que se muestra en la línea 7;
- líneas 47-54: se gestiona una posible excepción. Esta puede ser de dos tipos:
- la operación HTTP de la línea 31 ha fallado debido a un error de comunicación entre el servidor [nuxt] y el servidor PHP;
- la operación HTTP de la línea 31 se ha realizado con éxito, pero el resultado recibido ha señalado un error (líneas 39-42);
- línea 51: se observa que la sesión jSON con el servidor PHP no se ha iniciado;
- línea 53: se devuelve el resultado [result], que se muestra en la línea 7. Además, se configuran las propiedades [showErrorLoading] y [errorLoadingMessage] que el cliente [nuxt] utilizará para mostrar un mensaje de error cuando reciba la página enviada por el servidor [nuxt] (líneas 72-79);
- líneas 54-60: código que se ejecuta en todos los casos (tanto si se realiza con éxito como si falla);
- línea 56: se recupera la sesión [nuxt] en el contexto del servidor [nuxt];
- línea 57: se guarda;
- líneas 63-68: una vez finalizada la función [asyncData], el servidor [nuxt] ejecuta las funciones [beforeCreate] y [create];
Nota: la ejecución de la página [index] por parte del servidor [nuxt] puede fallar, por ejemplo, si el servidor de cálculo de impuestos no está en marcha cuando se inicia la aplicación [nuxt]:

En este caso, la única solución es iniciar primero el servidor de cálculo de impuestos y, a continuación, la propia aplicación [nuxt], ya que el menú de navegación no ofrece ninguna opción para iniciar una sesión jSON con el servidor de cálculo de impuestos;
15.14. La página [index] ejecutada por el cliente [nuxt]
La página [index] solo se ejecuta en el cliente [nuxt] después de que el servidor [nuxt] se la haya enviado. Este le ha enviado la información [result] y, en su caso, [showErrorLoading] y [errorLoadingMessage].
Sabemos que la función [asyncData] no se ejecutará. Quedan, pues, las funciones del ciclo de vida y, en particular, la función [mounted]:
mounted() {
console.log('[index mounted]')
// solo para clientes
if (this.showErrorLoading) {
console.log('[index mounted, showErrorLoading=true]')
this.$eventBus().$emit('errorLoading', true, this.errorLoadingMessage)
}
}
- el cliente [nuxt] integra automáticamente en las propiedades de la página los elementos [result] y, en su caso, [showErrorLoading, errorLoadingMessage] que le ha enviado el servidor [nuxt]:
- la propiedad [result] se muestra en la línea 7;
- las propiedades [showErrorLoading, errorLoadingMessage] son utilizadas por el método [mounted]: en la línea 4, se comprueba la propiedad [showErrorLoading]. Si es verdadera, en la línea 6 se utiliza el bus de eventos del cliente [nuxt] para indicar que hay un mensaje de error que mostrar;
- el evento [errorLoading], lanzado en la línea 6, es interceptado por la página [layouts/default] descrita en el apartado «enlace»;
15.15. La página [authentification], ejecutada por el servidor [nuxt]
La página [authentification] se encarga de identificar a un usuario ante el servidor de cálculo de impuestos. Su código es el siguiente:
<!-- página de autenticación -->
<template>
<Layout :left="true" :right="true">
<!-- navegación -->
<Navigation slot="left" />
<!-- mensaje-->
<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',
// componentes utilizados
components: {
Layout,
Navigation
},
// datos asíncronos
async asyncData(context) {
// registro
console.log('[authentification asyncData started]')
if (process.client) {
// Inicio de la espera del cliente [nuxt]
context.app.$eventBus().$emit('loading', true)
// sin errores
context.app.$eventBus().$emit('errorLoading', false)
}
try {
// se está realizando la autenticación en el servidor
const dao = context.app.$dao()
const response = await dao.authentifierUtilisateur('admin', 'admin')
// registro
console.log('[authentification asyncData response=]', response)
// resultado
const userAuthenticated = response.état === 200
// se registra si el usuario está autenticado o no
context.store.commit('replace', { userAuthenticated })
// se guarda el almacén en la sesión [nuxt]
const session = context.app.$session()
session.save(context)
// ¿Error de autenticación?
if (!userAuthenticated) {
// el error se encuentra en response.réponse
throw new Error(response.réponse)
}
// se obtiene el resultado
return { result: '[succès]' }
} catch (e) {
// se señala el error
return { result: '[échec]', showErrorLoading: true, errorLoadingMessage: e.message }
} finally {
// registro
console.log('[authentification asyncData finished]')
if (process.client) {
// fin de la espera del cliente [nuxt]
context.app.$eventBus().$emit('loading', false)
}
}
},
// ciclo de vida
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>
- línea 7: la página muestra el resultado [result] de la consulta asíncrona [asyncData] de las líneas 25-65;
- líneas 28-33: el servidor no ejecuta estas líneas destinadas al cliente [nuxt];
- línea 36: se recupera la capa [dao] del servidor [nuxt];
- línea 37: se realiza la autenticación en el servidor de cálculo de impuestos con las credenciales de prueba [admin, admin], que son las únicas aceptadas por dicho servidor;
- línea 41: la operación de autenticación se ha realizado con éxito solo si la respuesta es de estado 200;
- línea 43: se guarda en el almacén la propiedad [userAuthenticated];
- líneas 44-46: el almacén se guarda en la sesión [nuxt];
- líneas 48-51: si la autenticación ha fallado, se lanza una excepción con el mensaje de error que ha enviado el servidor de cálculo de impuestos;
- en caso contrario, en la línea 53, se devuelve un resultado de éxito que se mostrará en la línea 7;
- líneas 54-57: en caso de error, se establecen tres propiedades de la página [result, showErrorLoading, errorLoadingMessage]. La propiedad [result] se mostrará en la línea 7. Las tres propiedades se enviarán al cliente [nuxt];
- líneas 60-63: no son ejecutadas por el servidor [nuxt];
- una vez que [asyncData] ha devuelto su resultado, este se muestra en la línea 7. A continuación, se ejecutan los métodos [beforeCreate] (líneas 67-69) y [created] (líneas 70-72);
- ya está;
Nota: la ejecución de la página [authentification] por parte del servidor [nuxt] puede fallar, por ejemplo, si no se ha inicializado la sesión jSON con el servidor de cálculo de impuestos. Esto se puede solucionar de la siguiente manera:
- elimina la cookie de sesión PHP de tu navegador (para empezar de cero):

- inicie la aplicación [nuxt] sin que se haya iniciado el servidor de cálculo: aparecerá un error;
- inicia el servidor de cálculo del impuesto;
- introduzca URL [/authentification] directamente en la barra de direcciones del navegador:

En este caso, la única solución es volver a cargar la página [index].
15.16. La página [authentification] ejecutada por el cliente [nuxt]
Volvamos al código de la página:
<!-- página de autenticación -->
<template>
<Layout :left="true" :right="true">
<!-- navegación -->
<Navigation slot="left" />
<!-- mensaje-->
<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',
// componentes utilizados
components: {
Layout,
Navigation
},
// datos asíncronos
async asyncData(context) {
// registro
console.log('[authentification asyncData started]')
if (process.client) {
// Inicio de la espera del cliente [nuxt]
context.app.$eventBus().$emit('loading', true)
// sin errores
context.app.$eventBus().$emit('errorLoading', false)
}
try {
// se está realizando la autenticación en el servidor
const dao = context.app.$dao()
const response = await dao.authentifierUtilisateur('admin', 'admin')
// registro
console.log('[authentification asyncData response=]', response)
// resultado
const userAuthenticated = response.état === 200
// se registra si el usuario está autenticado o no
context.store.commit('replace', { userAuthenticated })
// se guarda el almacén en la sesión [nuxt]
const session = context.app.$session()
session.save(context)
// ¿Error de autenticación?
if (!userAuthenticated) {
// el error se encuentra en response.réponse
throw new Error(response.réponse)
}
// se devuelve el resultado
return { result: '[succès]' }
} catch (e) {
// se notifica el error
return { result: '[échec]', showErrorLoading: true, errorLoadingMessage: e.message }
} finally {
// registro
console.log('[authentification asyncData finished]')
if (process.client) {
// fin de la espera del cliente [nuxt]
context.app.$eventBus().$emit('loading', false)
}
}
},
// ciclo de vida
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>
Hay dos casos en los que el cliente [nuxt] ejecuta la página [authentification]:
- el cliente [nuxt] se ejecuta después de que el servidor [nuxt] haya enviado al navegador del cliente [nuxt] la página [authentification];
- el cliente [nuxt] porque el usuario ha hecho clic en el enlace [Authentification] del menú de navegación:

Analicemos primero el primer caso. En este caso, el cliente [nuxt] no ejecuta la función [asyncData]. Incorpora en las propiedades de la página los elementos [result] y, en su caso, [showErrorLoading, errorLoadingMessage] que le ha enviado el servidor [nuxt]:
- la propiedad [result] se muestra en la línea 7;
- las propiedades [showErrorLoading, errorLoadingMessage] se utilizan mediante el método [mounted]: en la línea 79, se comprueba la propiedad [showErrorLoading]. Si es verdadera, en la línea 81 se utiliza el bus de eventos del cliente [nuxt] para indicar que hay un mensaje de error que mostrar;
El mecanismo de visualización del mensaje de error se ha explicado para la página [index] en el apartado «enlace».
El caso 2 corresponde al cliente [nuxt], que se ejecuta cuando el usuario hace clic en el enlace [Authentification]. En este caso, el cliente [nuxt] se ejecuta de forma autónoma y no después del servidor [nuxt]. A continuación, se ejecuta la función [asyncData]. Solo indicamos los detalles que difieren de las explicaciones dadas para la página ejecutada por el servidor [nuxt]:
- líneas 28-33: el cliente [nuxt] solicita que se muestre el mensaje de espera y que desaparezca cualquier mensaje de error que se hubiera mostrado anteriormente;
- línea 36: ahora es la capa [dao] del cliente [nuxt] la que se obtiene aquí;
- líneas 60-63: el cliente [nuxt] solicita que se deje de mostrar el mensaje de espera;
- una vez finalizada la función [asyncData], se iniciará el ciclo de vida de la página. Se ejecutará la función [mounted] de las líneas 76-83. Si se ha producido un error, se mostrará el mensaje de error;
Nota: para provocar un error, sigue el procedimiento explicado para el servidor [nuxt] al final del párrafo del enlace, pero en lugar de solicitar la página [authentification] escribiendo su URL en la barra de direcciones, utilice el enlace [Authentification] del menú de navegación. De este modo, se ejecutará el cliente [nuxt].
15.17. La página [get-admindata]
El código de la página [get-admindata] es el siguiente:
<!-- vista get-admindata -->
<template>
<Layout :left="true" :right="true">
<!-- navegación -->
<Navigation slot="left" />
<!-- mensaje -->
<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',
// componentes utilizados
components: {
Layout,
Navigation
},
// datos asíncronos
async asyncData(context) {
// registro
console.log('[get-admindata asyncData started]')
if (process.client) {
// Inicio de la espera
context.app.$eventBus().$emit('loading', true)
// sin errores
context.app.$eventBus().$emit('errorLoading', false)
}
try {
// se solicitan los datos [admindata]
const response = await context.app.$dao().getAdminData()
// registro
console.log('[get-admindata asyncData response=]', response)
// resultado
const adminData = response.état === 1000 ? response.réponse : ''
// se guarda el dato en el almacén
context.store.commit('replace', { adminData })
// se guarda el almacén en la sesión [nuxt]
const session = context.app.$session()
session.save(context)
// ¿Se ha producido algún error?
if (!adminData) {
// el error se encuentra en response.réponse
throw new Error(response.réponse)
}
// se devuelve el valor recibido
return { result: adminData }
} catch (e) {
// se notifica el error
return { result: '[échec]', showErrorLoading: true, errorLoadingMessage: e.message }
} finally {
// registro
console.log('[get-admindata asyncData finished]')
if (process.client) {
// fin de la espera
context.app.$eventBus().$emit('loading', false)
}
}
},
// ciclo de vida
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>
Esta página es muy similar a la página [authentification]. Las explicaciones son análogas tanto para su ejecución por parte del servidor [nuxt] como para su ejecución por parte del cliente [nuxt]. Cabe señalar, sin embargo, que la línea 7 no muestra «éxito» o «fracaso» como anteriormente, sino el valor de los datos recibidos del servidor de cálculo de impuestos (línea 52):

El resultado anterior se obtiene tanto con el servidor como con el cliente [nuxt]. Para provocar un error, solicita la página [get-admindata], a través del servidor o del cliente [nuxt], sin estar autenticado:

15.18. La página [fin-session]
El código de la página es el siguiente:
<!-- página principal -->
<template>
<Layout :left="true" :right="true">
<!-- navegación -->
<Navigation slot="left" />
<!-- mensaje-->
<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',
// componentes utilizados
components: {
Layout,
Navigation
},
// datos asíncronos
async asyncData(context) {
// registro
console.log('[fin-session asyncData started]')
// caso del cliente [nuxt]
if (process.client) {
// Inicio de la espera
context.app.$eventBus().$emit('loading', true)
// sin errores
context.app.$eventBus().$emit('errorLoading', false)
}
try {
// se solicita una nueva sesión PHP al servidor de cálculo de impuestos
const dao = context.app.$dao()
const response = await dao.finSession()
// registro
console.log('[fin-session asyncData response=]', response)
// ¿Se ha producido algún error?
if (response.état !== 400) {
// el error se encuentra en response.réponse
throw new Error(response.réponse)
}
// El servidor ha enviado una nueva cookie de sesión PHP
// se recupera tanto para el servidor como para el cliente Nuxt
// si el cliente ejecuta este código [nuxt], la cookie de sesión PHP debe añadirse a la sesión de Nuxt
// para que el plugin [plgDao] del servidor [nuxt] pueda recuperarla e inicializar la capa [dao] con
//. Si este código lo ejecuta el servidor [nuxt], la cookie de sesión PHP debe introducirse en la sesión de Nuxt
// para que el enrutamiento del cliente [nuxt] la recupere y la pase al navegador
const phpSessionCookie = dao.getPhpSessionCookie()
//: se registra en el almacén que la sesión jSON se ha iniciado y se almacena la cookie de sesión PHP
context.store.commit('replace', { jsonSessionStarted: true, phpSessionCookie, userAuthenticated: false, adminData: '' })
// se guarda el almacén en la sesión [nuxt]
const session = context.app.$session()
session.save(context)
// se devuelve el resultado
return { result: "[succès]. La session jSON reste initialisée mais vous n'êtes plus authentifié(e)." }
} catch (e) {
// registro
console.log('[fin-session asyncData error=]', e)
// se notifica el error
return { result: '[échec]', showErrorLoading: true, errorLoadingMessage: e.message }
} finally {
// registro
console.log('[fin-session asyncData finished]')
if (process.client) {
// fin de la espera
context.app.$eventBus().$emit('loading', false)
}
}
},
// ciclo de vida
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>
El código es muy similar al de las páginas anteriores y las explicaciones son las mismas. Solo hay que fijarse en un punto: la operación asíncrona de la línea 38 hace que el servidor de cálculo de impuestos envíe una nueva cookie de sesión PHP. Las explicaciones sobre la gestión de esta cookie varían en función de si es el servidor o el cliente [nuxt] el que ejecuta este código.
Empecemos por el servidor [nuxt]:
- línea 37: se instancia la capa [dao] del servidor [nuxt]. Recordemos el código de su constructor:
// creador
constructor(axios, phpSessionCookie) {
// biblioteca Axios
this.axios = axios
// valor de la cookie de sesión
this.phpSessionCookie = phpSessionCookie
// nombre de la cookie de sesión del servidor PHP
this.phpSessionCookieName = 'PHPSESSID'
}
En la línea 1 vemos que el constructor necesita la cookie de sesión PHP del momento, la última recibida, ya sea por el servidor o por el cliente [nuxt];
- línea 52: el servidor [nuxt] recupera la cookie de la nueva sesión PHP o bien la cookie anterior si la operación de cierre de sesión ha fallado;
- línea 54: la cookie de sesión PHP se coloca en el almacén y, a continuación, se guarda en la sesión [nuxt] en las líneas 56-57;
- a continuación, tras el servidor, es el cliente [nuxt] el que ejecuta la página [fin-session] con los datos enviados por el servidor. Sabemos que no va a ejecutar la función [asyncData];
- al final, una vez que el servidor y el cliente [nuxt] han terminado su trabajo, sabemos que la cookie PHP, necesaria para las comunicaciones con el servidor de cálculo de impuestos, se encuentra en la sesión [nuxt];
El hecho de que la cookie PHP se encuentre en la sesión [nuxt] es suficiente para el servidor, ya que es de ahí de donde la obtendrá su capa [dao]. En el plugin [server/plgDao], que inicializa la capa [dao] del servidor, se ha escrito:
/* eslint-disable no-console */
// se crea un punto de acceso a la capa [Dao]
import Dao from '@/api/server/Dao'
export default (context, inject) => {
// configuración de Axios
context.$axios.defaults.timeout = context.env.timeout
context.$axios.defaults.baseURL = context.env.baseURL
// se recupera la cookie de sesión
const store = context.app.$session().value.store
const phpSessionCookie = store ? store.phpSessionCookie : ''
console.log('session=', context.app.$session().value, 'phpSessionCookie=', phpSessionCookie)
// instanciación de la capa [dao]
const dao = new Dao(context.$axios, phpSessionCookie)
// inyección de una función [$dao] en el contexto
inject('dao', () => dao)
// registro
console.log('[fonction server $dao créée]')
}
- en la línea 13, se instancia la capa [dao] del servidor [nuxt] con la cookie de sesión PHP obtenida de la sesión [nuxt], líneas 9-10;
En el caso del cliente [nuxt], la cosa cambia. De hecho, no es él quien envía la cookie, sino el navegador que lo ejecuta. Sin embargo, este navegador no conoce la cookie de la nueva sesión PHP recibida por el servidor [nuxt]. Si utilizamos los enlaces del menú de navegación [3]:

El servidor de cálculo de impuestos recibirá del navegador una cookie de sesión obsoleta, PHP, y responderá que a dicha cookie no hay ninguna sesión asociada, jSON. Tenemos que encontrar la forma de enviar al navegador la nueva cookie de sesión, PHP.
Para ello, podemos utilizar un middleware de enrutamiento:

El script [client/routing] es el middleware de enrutamiento declarado en el archivo [nuxt.config]:
// enrutador
router: {
// raíz de los URL de la aplicación
base: '/nuxt-12/',
// middleware de enrutamiento
middleware: ['routing']
},
El script [middleware/routing] es el siguiente:
/* eslint-disable no-console */
// importamos el middleware del cliente
import clientRouting from './client/routing'
export default function(context) {
// ¿Quién ejecuta este código?
console.log('[middleware], process.server', process.server, ', process.client=', process.client)
if (process.client) {
// enrutamiento del cliente
clientRouting(context)
}
}
- líneas 9-12: solo se redirige al cliente mediante una función importada en la línea 4;
El script [middleware/client/routing] es el siguiente:
/* eslint-disable no-console */
export default function(context) {
// ¿Quién ejecuta este código?
console.log('[middleware client], process.server', process.server, ', process.client=', process.client)
// gestión de la cookie de sesión PHP en el navegador
// La cookie de sesión PHP del navegador debe ser idéntica a la que se encuentra en la sesión de Nuxt
// la acción [fin-session] recibe una nueva cookie PHP (tanto el servidor como el cliente Nuxt)
// si es el servidor quien la recibe, el cliente debe transmitirla al navegador
// para sus propias comunicaciones con el servidor PHP
//: aquí nos encontramos en un enrutamiento del cliente
// se recupera la cookie de sesión PHP
const phpSessionCookie = context.store.state.phpSessionCookie
if (phpSessionCookie) {
// si existe, se asigna la cookie de sesión PHP al navegador
document.cookie = phpSessionCookie
}
}
Volvamos a la situación justo después de que el servidor [nuxt] haya ejecutado la página [fin-session]:

Si hacemos clic en uno de los enlaces del menú [3], el cliente [nuxt] tomará el control. Como se va a producir un cambio de página, se ejecutará el script de enrutamiento del cliente:
- línea 13: se encuentra la cookie de sesión PHP en el almacén de la aplicación [nuxt];
- línea 14: si no está vacía, se transmite al navegador (línea 16). A partir de ese momento, el navegador del cliente [nuxt] dispone de la cookie de sesión correcta PHP;
El script [client/routing] se ejecuta cada vez que el cliente [nuxt] cambia de página. El código del script es válido independientemente de la página de destino: simplemente, la mayoría de las veces, proporciona al navegador una cookie de sesión PHP que ya tiene, salvo en dos casos:
- justo después de iniciar la aplicación, el servidor [nuxt] ejecuta la página [index] y recibe una primera cookie de sesión PHP que el navegador del cliente [nuxt] no tiene;
- cuando el servidor [nuxt] ejecuta la página [fin-session] tal y como se acaba de explicar;
Ahora analicemos el caso en el que la página [fin-session] la ejecuta únicamente el cliente [nuxt], porque se ha hecho clic en su enlace del menú de navegación. Ahora es el cliente [nuxt] el que ejecuta la función [asyncData]:
try {
// se solicita una nueva sesión PHP al servidor de cálculo de impuestos
const dao = context.app.$dao()
const response = await dao.finSession()
// registro
console.log('[fin-session asyncData response=]', response)
// ¿Se ha producido algún error?
if (response.état !== 400) {
// el error se encuentra en response.réponse
throw new Error(response.réponse)
}
// El servidor ha enviado una nueva cookie de sesión PHP
// se recupera tanto para el servidor como para el cliente Nuxt
// si el cliente ejecuta este código [nuxt], la cookie de sesión PHP debe añadirse a la sesión de Nuxt
// para que el plugin [plgDao] del servidor [nuxt] pueda recuperarla e inicializar la capa [dao] con
//. Si este código lo ejecuta el servidor [nuxt], la cookie de sesión PHP debe introducirse en la sesión de Nuxt
// para que el enrutamiento del cliente [nuxt] la recupere y la pase al navegador
const phpSessionCookie = dao.getPhpSessionCookie()
//: se registra en el almacén que la sesión jSON se ha iniciado y se almacena la cookie de sesión PHP
context.store.commit('replace', { jsonSessionStarted: true, phpSessionCookie, userAuthenticated: false, adminData: '' })
//: se guarda el almacén en la sesión [nuxt]
const session = context.app.$session()
session.save(context)
// se devuelve el resultado
return { result: "[succès]. La session jSON reste initialisée mais vous n'êtes plus authentifié(e)." }
} catch (e) {
// registro
console.log('[fin-session asyncData error=]', e)
// se notifica el error
return { result: '[échec]', showErrorLoading: true, errorLoadingMessage: e.message }
} finally {
// registro
console.log('[fin-session asyncData finished]')
if (process.client) {
// fin de la espera
context.app.$eventBus().$emit('loading', false)
}
}
- línea 3: aquí se obtiene la capa [dao] del cliente [nuxt];
- línea 18: la cookie de sesión PHP, recuperada por la capa [dao] del cliente [nuxt], se almacena en el store (línea 20) y, a continuación, guardada en la sesión [nuxt] (líneas 22-23);
- a partir de ahí todo va bien, ya que sabemos que la capa [dao] del servidor [nuxt] va a buscar la cookie de sesión PHP en la sesión [nuxt];
15.19. Exécution
Para ejecutar este ejemplo, hay que asegurarse, antes de la ejecución, de eliminar la cookie de sesión [nuxt] y la cookie PHP del navegador que ejecuta el cliente [nuxt], con el fin de partir de una situación limpia. A continuación se muestra un ejemplo con el navegador Chrome:

15.20. Conclusion
Este ejemplo resultó especialmente complejo. Reunía los conocimientos adquiridos en los ejemplos anteriores: persistencia del almacén en una sesión [nuxt], complementos de inyección de funciones, middleware de enrutamiento y gestión de errores en operaciones asíncronas. La complejidad se vio incrementada por el hecho de que queríamos que el usuario pudiera tanto utilizar los enlaces del menú de navegación como escribir URL manualmente sin que ello provocara un fallo en la aplicación. Para ello, nos vimos obligados a analizar cómo se comportaba cada página en función de si se ejecutaba en el cliente o en el servidor [nuxt].
Esta unidad de comportamiento del cliente y del servidor [nuxt] no es imprescindible. Podemos plantearnos el caso frecuente en el que:
- la primera página la sirve el servidor [nuxt];
- todas las páginas siguientes son servidas por el cliente [nuxt], que entonces funciona en modo [SPA];
No obstante, incluso en este caso, hay que comprobar qué resultado da la ejecución de todas las páginas por parte del servidor [nuxt], ya que eso es lo que obtendrán los motores de búsqueda que las soliciten.