12. Proyecto [vuejs-10]: complemento [dao], solicitudes asincrónicas HTTP
La estructura del proyecto [vuejs-10] es la siguiente:

El proyecto [vuejs-10] muestra un componente que realiza una solicitud HTTP a un servidor remoto. La arquitectura utilizada es la siguiente:

Un componente [Vue.js] utiliza la capa [dao] para comunicarse con el servidor de cálculo de impuestos.
12.1. Instalación de las dependencias
La aplicación [vuejs-10] utiliza la biblioteca [axios] para realizar las consultas asincrónicas al servidor de cálculo de impuestos. Debemos instalar esta dependencia:

- en [4-5], la línea agregada al archivo [package.json] tras la instalación de la biblioteca [axios] [1-3];
12.2. La clase [Dao]
La clase [Dao] es la que se desarrolló en el párrafo [La classe Dao]. La volvemos a presentar aquí a modo de recordatorio:
'use strict';
// importaciones
import qs from 'qs'
// clase [Dao]
class Dao {
// constructor
constructor(axios) {
this.axios = axios;
// cookie de sesión
this.sessionCookieName = "PHPSESSID";
this.sessionCookie = '';
}
// iniciar 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 presentar 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 respuesta en sí)
// se recupera la cookie de sesión, si existe
const setCookie = response.headers['set-cookie'];
if (setCookie) {
// setCookie es un array
// se busca la cookie de sesión en esta tabla
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 guarda la cookie de sesión
// eslint-disable-next-line require-atomic-updates
this.sessionCookie = results[1];
// la encontramos
trouvé = true;
} else {
// el siguiente elemento
i++;
}
}
}
// la respuesta del servidor está en [response.data]
return response.data;
}
}
// exportación de la clase
export default Dao;
El proyecto [vuejs-10] utiliza únicamente el método asíncrono [initSession] de las líneas 18 a 30. Cabe recordar que la clase [Dao] se instancia con un parámetro [axios], en la línea 10, parámetro inicializado por el código que la invoca. Este código que la invoca será, en este caso, el script [./main.js].
12.3. El complemento [pluginDao]
El complemento [pluginDao] es el siguiente:
export default {
install(Vue, dao) {
// agrega una propiedad [$dao] a la clase Vue
Object.defineProperty(Vue.prototype, '$dao', {
// cuando se hace referencia a Vue.$dao, se devuelve el segundo parámetro [dao]
get: () => dao,
})
}
}
Si recordamos la explicación dada para el complemento [event-bus], vemos que el complemento [pluginDao] crea, en la clase o función [Vue], una nueva propiedad llamada [$dao]. Esta propiedad tendrá (aún queda por demostrar) como valor el objeto exportado por el script [./Dao], es decir, la clase [Dao] anterior.
12.4. El script principal [main.js]
El código del script principal [main.js] es el siguiente:
// importaciones
import Vue from 'vue'
import App from './App.vue'
import axios from 'axios';
// plugins
import BootstrapVue from 'bootstrap-vue'
Vue.use(BootstrapVue);
// bootstrap
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
// capa [dao]
import Dao from './Dao';
// configuración de Axios
axios.defaults.timeout = 2000;
axios.defaults.baseURL = 'http://localhost/php7/scripts-web/impuestos/versión-14';
axios.defaults.withCredentials = true;
// instanciación de la capa [dao]
const dao = new Dao(axios);
// complemento [dao]
import pluginDao from './plugins/dao'
Vue.use(pluginDao, dao)
// configuración
Vue.config.productionTip = false
// instanciación del proyecto [App]
new Vue({
render: h => h(App),
}).$mount('#app')
El script [main.js]:
- instancia la capa [dao] en las líneas 14-21;
- incorpora el complemento [pluginDao] en las líneas 24-25;
- línea 15: se importa la clase [Dao];
- líneas 17-18: se configura el objeto [axios] que ejecuta las consultas HTTP. Este objeto se importa en la línea 4;
- línea 17: definición de un [timeout] de 2 segundos;
- línea 18: el URL del servidor de cálculo de impuestos;
- línea 19: para poder intercambiar cookies con el servidor;
- líneas 24-25: uso del complemento [pluginDao]
- línea 24: importación del complemento;
- línea 25: integración del complemento. Se observa que el segundo parámetro del método [Vue.use] es la referencia de la capa [dao] definida en la línea 21. Por esta razón, la propiedad [Vue.$dao] hará referencia a la capa [dao] en todas las instancias de la clase o función [Vue], es decir, en todos los componentes [Vue.js];
12.5. La vista principal [App.vue]
El código de la vista principal [App] es el siguiente:
<template>
<div class="container">
<b-card>
<!-- mensaje -->
<b-alert show variant="success" align="center">
<h4>[vuejs-10] : plugin [dao], requêtes HTTP asynchrones</h4>
</b-alert>
<!-- componente que realiza una consulta asíncrona al servidor de cálculo de impuestos-->
<Component1 @error="doSomethingWithError" @endWaiting="endWaiting" @beginWaiting="beginWaiting" />
<!-- visualización de un posible error -->
<b-alert show
variant="danger"
v-if="showError">Evénement [error] intercepté par [App]. Valeur reçue = {{error}}</b-alert>
<!-- mensaje de espera con un indicador de carga -->
<b-alert show v-if="showWaiting" variant="light">
<strong>Requête au serveur de calcul d'impôt en cours...</strong>
<b-spinner variant="primary" label="Spinning"></b-spinner>
</b-alert>
</b-card>
</div>
</template>
<script>
import Component1 from "./components/Component1";
export default {
name: "app",
// estado del componente
data() {
return {
// controla el indicador de espera
showWaiting: false,
// controla la visualización del error
showError: false,
// el error interceptado
error: {}
};
},
// componentes utilizados
components: {
Component1
},
// métodos de gestión de eventos
methods: {
// inicio de la espera
beginWaiting() {
// se muestra la espera
this.showWaiting = true;
// se oculta el mensaje de error
this.showError = false;
},
// fin de la espera
endWaiting() {
// se oculta la espera
this.showWaiting = false;
},
// manejo de errores
doSomethingWithError(error) {
// se indica que hubo un error
this.error = error;
// se muestra el mensaje de error
this.showError = true;
}
}
};
</script>
Comentarios
- línea 9: [Component1] es el componente que realiza la consulta asíncrona HTTP. Puede emitir tres eventos:
- [beginWaiting]: la consulta está por realizarse. Se debe mostrar un mensaje de espera al usuario;
- [endWaiting]: la consulta ha finalizado. Se debe detener la espera;
- [error]: la consulta falló. Se debe mostrar un mensaje de error;
- líneas 10-13: la alerta que muestra el posible mensaje de error. Está controlada por la variable booleana [showError] de la línea 33. Muestra el error de la línea 35;
- líneas 14-18: la alerta que muestra el mensaje de espera con un indicador de carga. Está controlada por la variable booleana [showWaiting] de la línea 47;
- líneas 45-50: [beginWaiting] es el método que se ejecuta al recibir el evento [beginWaiting]. Muestra el mensaje de espera (línea 47) y oculta el mensaje de error (línea 49) en caso de que este último esté visible como resultado de una operación anterior;
- líneas 52-55: [endWaiting] es el método que se ejecuta al recibir el evento [endWaiting]. Oculta el mensaje de espera (línea 54);
- líneas 57-62: [doSomethingWithError] es el método que se ejecuta al recibir el evento [error]. Registra el error recibido (línea 59) y muestra el mensaje de error (línea 61);
12.6. El componente [Component1]
El código del componente [Component1] es el siguiente:
<template>
<b-row>
<b-col>
<b-alert show
variant="warning"
v-if="showMsg">Valeur reçue du serveur = {{data}}</b-alert>
</b-col>
</b-row>
</template>
<script>
export default {
name: "component1",
// estado del componente
data() {
return {
showMsg: false
};
},
// métodos de gestión de eventos
methods: {
// procesamiento de los datos recibidos del servidor
doSomethingWithData(data) {
// se registran los datos recibidos
this.data = data;
// se muestran
this.showMsg = true;
}
},
// se acaba de crear el componente
created() {
// se inicializa la sesión con el servidor: solicitud asíncrona
// se utiliza la promesa devuelta por los métodos de la capa [dao]
// se notifica el inicio de la operación
this.$emit("beginWaiting");
// se inicia la operación asíncrona
this.$dao
// se trata de inicializar una sesión jSON con el servidor de cálculo de impuestos
.initSession()
// método que procesa los datos recibidos en caso de éxito
.then(data => {
// se procesan los datos recibidos
this.doSomethingWithData(data);
})
// método que procesa el error en caso de que se produzca
.catch(error => {
// se reporta el error al componente padre
this.$emit("error", error.message);
}).finally(() => {
// fin de la espera
this.$emit("endWaiting");
})
}
};
</script>
Comentarios
- líneas 4-6: el componente consta de una única alerta que muestra el valor devuelto por el servidor de cálculo de impuestos, pero solo si la consulta HTTP se realiza con éxito. Esta alerta está controlada por el valor booleano [showMsg] de la línea 17;
- líneas 31-53: la consulta HTTP se realiza tan pronto como se crea el componente. Por lo tanto, su código se coloca en el método [created] de la línea 31;
- línea 35: se le indica al componente padre que la consulta asíncrona está a punto de iniciarse;
- líneas 37-39: se ejecuta el método [this.$dao.initSession]. Este inicia una sesión jSON con el servidor de cálculo de impuestos. El resultado inmediato de este método es un [Promise];
- líneas 41-44: este código se ejecuta cuando el servidor ha devuelto su resultado sin errores. El resultado del servidor se encuentra en [data]. En la línea 43, se le pide al método [doSomethingWithData] que procese este resultado;
- líneas 46-49: este código se ejecuta en caso de error durante la ejecución de la consulta. En la línea 48, se le indica al componente padre que se ha producido un error y se le pasa el mensaje de error [error.message];
- líneas 49-52: este código se ejecuta en todos los casos. Se le indica al componente padre que la solicitud HTTP ha finalizado;
- líneas 23-28: el método [doSomethingWithData] es el encargado de procesar los datos [data] enviados por el servidor. En la línea 25, se registran estos datos y en la línea 27 se muestran;
12.7. Ejecución del proyecto

Si al iniciar el proyecto el servidor de cálculo de impuestos no está en ejecución, se obtiene el siguiente resultado:

Iniciemos el servidor [Laragon] (véase https://tahe.developpez.com/tutoriels-cours/php7) y recarguemos la página anterior. El resultado es entonces el siguiente:

Nota: aquí utilizamos la versión 14 del servidor de cálculo de impuestos definida en https://tahe.developpez.com/tutoriels-cours/php7.