12. De JavaScript-functies van HTTP

12.1. Keuze van een bibliotheek: HTTP
We hebben hier gekozen voor twee bibliotheken:
EcmaScript 6 beschikt standaard over een functie HTTP, genaamd [fetch], die niet is geïmplementeerd door [node.js] (sept. 2019). Er bestaat een bibliotheek met de naam [node-fetch] waarmee de functie [fetch] onder Node kan worden gebruikt. Deze bibliotheek maakt gebruik van bepaalde API die specifiek zijn voor [node.js]. Een [node-fetch]-code is dan mogelijk niet 100% overdraagbaar naar een niet-[node]-omgeving, bijvoorbeeld in een browser;
Er bestaat overigens een bibliotheek met de naam [axios] die is bedoeld voor HTTP-verzoeken en die zowel compatibel is met [node.js] als met browsers. Het is deze bibliotheek die we uiteindelijk zullen gebruiken.
We zullen hetzelfde script presenteren dat met beide bibliotheken is geschreven, om aan te tonen dat de manier van programmeren met beide bibliotheken vergelijkbaar is.
12.2. Een werkomgeving opzetten
12.2.1. Installatie van de belastingberekeningsserver
Uiteindelijk gaan we een webapplicatie schrijven met de volgende architectuur:

JS: JavaScript
De JavaScript-code is client-side:
- van een service met statische pagina's of fragmenten;
- van een jSON-service;
De JavaScript-code is dus een client jSON en kan als zodanig worden ingedeeld in lagen [UI, métier, dao] (UI: gebruikersinterface), net zoals onze jSON-clients die in PHP zijn geschreven.
De server is dezelfde als die voor de belastingberekening, waarvan we al 13 versies hebben geschreven. We gaan een 14e versie schrijven. We beginnen dus met het dupliceren, in NetBeans, van de map van versie 13 naar de map van versie 14:

- naar [6]. Vervolgens passen we het bestand [config.json] van versie 14 als volgt aan:
{
"databaseFilename": "Config/database.json",
"rootDirectory": "C:/myprograms/laragon-lite/www/php7/scripts-web/impots/version-14",
"relativeDependencies": [
"/Entities/BaseEntity.php",
"/Entities/Simulation.php",
...
"vues": {
"vue-authentification.php": [700, 221, 400],
"vue-calcul-impot.php": [200, 300, 341, 350, 800],
"vue-liste-simulations.php": [500, 600]
},
"vue-erreurs": "vue-erreurs.php"
}
- op regel 3 wijzigen we de hoofdmap van de applicatie;
Om toegang te krijgen tot deze server, moeten de diensten [Laragon] worden gestart.
Zodra dit is gebeurd, kunnen we met [Postman] (zie artikel via de link) deze nieuwe versie van de server testen, die voorlopig identiek is aan versie 13. We kunnen de verzameling verzoeken gebruiken die is gebruikt om versie 12 van de belastingberekeningsserver te testen:

- in [1-4] de query [init-session-700] gebruiken om een sessie jSON te initialiseren;
- in [4-5] moet u [version-14] invoeren in plaats van [version-12] om versie 14 van het project te testen;
- tijdens de uitvoering moet het antwoord jS0N [6] van de server worden ontvangen;
Versie 14 van de server is nu operationeel. We zullen deze nog enigszins aanpassen. Laten we nog eens kijken naar de API van deze server:
Actie | Rol | Uitvoeringscontext |
init-session | Wordt gebruikt om het type (json, xml, html) van de gewenste antwoorden vast te leggen | Verzoek GET main.php?action=init-session&type=x kan op elk moment worden verzonden |
authentifier-utilisateur | Geeft een gebruiker al dan niet toestemming om in te loggen | Verzoek POST main.php?action=authentifier-utilisateur Het verzoek moet twee POST-parameters bevatten [user, password] Kan alleen worden verzonden als het sessietype (json, xml, html) bekend is |
belasting-berekenen | Voert een simulatie van de belastingberekening uit | Verzoek POST main.php?action=belasting-berekenen De aanvraag moet drie POST-parameters bevatten: [marié, enfants, salaire] Kan alleen worden verzonden als het sessietype (json, xml, html) bekend is en de gebruiker is geauthenticeerd |
lister-simulations | Vraagt om de lijst met simulaties die sinds het begin van de sessie zijn uitgevoerd | Verzoek GET main.php?action=lister-simulations Het verzoek accepteert geen andere parameters Kan alleen worden verzonden als het type van de sessie (json, xml, html) bekend is en de gebruiker is geauthenticeerd |
simulatie verwijderen | Verwijdert een simulatie uit de lijst met simulaties | Verzoek GET main.php?action=lister-simulations&nummer=x Het verzoek accepteert geen andere parameters Kan alleen worden verzonden als het type van de sessie (json, xml, html) bekend is en de gebruiker is geauthenticeerd |
sessie-beëindigen | Beëindigt de simulatiesessie. | Technisch gezien wordt de oude websessie verwijderd en wordt er een nieuwe sessie aangemaakt Kan alleen worden verzonden als het type van de sessie (json, xml, html) bekend is en de gebruiker is geauthenticeerd |
12.2.2. Installatie van de HTTP-bibliotheken van de JavaScript-client
In eerste instantie zullen we met de volgende architectuur werken:

- in [1] voert een consolescript [node.js] een verzoek HTTP uit naar de server jSON voor de belastingberekening;
- in [4] ontvangt het dit antwoord en geeft het weer op de console;
In voorbeeld nr. 1 gebruiken we de bibliotheken [node-fetch] en [axios], waarna we voor de volgende voorbeelden alleen [axios] behouden. We installeren nu deze twee JavaScript-bibliotheken vanuit de terminal van [VSCode]:

We zullen ook de bibliotheek [qs] gebruiken, waarmee een tekenreeks kan worden gecodeerd met URL. We herinneren ons dat deze codering wordt gebruikt om de parameters van een verzoek HTTP, GET of POST te coderen.

12.3. script [fetch-01]
Het script [fetch-01] gebruikt de bibliotheek [node-fetch] om een sessie jSON met de belastingberekeningsserver te initialiseren. De code ervan is als volgt:
'use strict';
// imports
import fetch from 'node-fetch';
import qs from 'qs';
import { sprintf } from 'sprintf-js';
import moment from 'moment';
// URL basis van de belastingberekeningsserver
const baseUrl = 'http://localhost/php7/scripts-web/impots/version-14/main.php?';
// sessie starten
async function initSession() {
// opties van de query HHTP [get /main.php?action=init-session&type=json]
const options = {
method: "GET",
timeout: 2000
};
// uitvoering van de query HTTP [get /main.php?action=init-session&type=json]
let débutFetch;
try {
// asynchrone aanvraag – [fetch] levert een belofte op
débutFetch = moment(Date.now());
const response = await fetch(baseUrl + qs.stringify({
action: 'init-session',
type: 'json'
}), options);
// [response] is het volledige antwoord HTTP van de server (HTTP-headers + het antwoord zelf)
// we geven dit antwoord weer om de structuur ervan te bekijken
console.log(sprintf("réponse fetch formatée en json,=%j, %s", response, heure(débutFetch)));
console.log("réponse fetch en javascript=", response);
// de headers HTTP zijn beschikbaar
console.log("entêtes de la réponse=", response.headers);
// als het antwoord van het type application/json is, wordt het JSON-antwoord van de server verkregen met de asynchrone functie [response.json()]
// in dit geval ontvangt de aanroepende code een object [Promise]
// [await] maakt het mogelijk om het antwoord [json] van de server te verkrijgen in plaats van de belofte
const débutJson = moment(Date.now());
const objet = await response.json();
console.log(sprintf("réponse json=%j, type=%s, %s", objet, typeof (objet), heure(débutJson)));
return objet;
// als het antwoord van het type text/plain is, wordt het tekstantwoord van de server verkregen met [response.text()]
// in dit geval ontvangt de aanroepende code een object [Promise]
// Met [await] kan het antwoord [texte] van de server worden opgehaald in plaats van de belofte
// const text = await response.text();
// console.log("tekstantwoord=", text);
// return text;
} catch (error) {
// we zijn hier omdat de server een foutcode [404 Not Found, ...] heeft verzonden, vergezeld van een lege inhoud – we geven de fout weer om de structuur ervan te bekijken
// of omdat de client [fetch] een uitzondering heeft gegenereerd (netwerk niet bereikbaar, ...)
// de structuur van de fout wordt weergegeven
console.log(sprintf("error fetch en json=%j, %s", error, heure(débutFetch)));
console.log("error fetch en javascript=", typeof (error), error);
// de ontvangen foutmelding wordt weergegeven
throw error.message;
}
}
// de functie main voert de asynchrone functie [initSession] uit
async function main() {
try {
console.log("requête HTTP vers le serveur en cours ---------------------------------------------");
const response = await initSession();
console.log("succès ---------------------------------------------");
console.log("réponse=", response, typeof (response))
} catch (error) {
console.log("erreur ---------------------------------------------");
console.log("erreur=", error, typeof (error));
}
}
// test
main();
// hulpprogramma voor het weergeven van tijd en duur
function heure(début) {
// huidige tijd
const now = moment(Date.now());
// tijdopmaak
let result = "heure=" + now.format("HH:mm:ss:SSS");
// moet er een duur worden berekend?
if (début) {
const durée = now - début;
const milliseconds = durée % 1000;
const seconds = Math.floor(durée / 1000);
// opmaak van tijd + duur
result = result + sprintf(", durée= %s seconde(s) et %s millisecondes", seconds, milliseconds);
}
// resultaat
return result;
}
Opmerkingen
- de JavaScript-functies HTTP zijn asynchrone functies. We passen hier toe wat we in de vorige paragraaf hebben geleerd (zie link);
- regel 24: om te wachten tot het antwoord van de asynchrone functie [fetch] wordt gepubliceerd in de gebeurtenislus van [node.js], gebruiken we het sleutelwoord [await]. We weten dat deze instructie moet staan in code die wordt voorafgegaan door het sleutelwoord [async] (regel 13);
- regels 13-56: we de code HTTP in de asynchrone functie [initSession] inkapselen;
- regels 59-69: een tweede asynchrone functie [main] wordt gebruikt om de asynchrone functie [initSession] op een blokkerende manier (async/await) aan te roepen;
- regel 72: de asynchrone functie [main] wordt aangeroepen;
- hoewel de hele code op synchrone code lijkt, worden er wel degelijk asynchrone functies uitgevoerd, maar op een blokkerende manier;
- regel 19: om een sessie jSON met de belastingberekeningsserver te initialiseren, moet het commando HTTP [get /main.php?action=init-session&type=json] naar de server worden verzonden. Dat is wat de code in de regels 24-27 doet. De syntaxis van [fetch] is als volgt: [fetch(URL, options)] met:
- [URL]: de opgevraagde URL;
- [options]: een object dat de opties van de query definieert. Hier worden met name de headers HTTP gedefinieerd die naar de doelmachine moeten worden verzonden;
- regels 15-18: hier worden de opties gedefinieerd voor de aanvraag die men wil uitvoeren:
- [method]: we willen een GET uitvoeren;
- [timeout]: we willen dat de client [fetch] niet langer dan 2 seconden wacht op het antwoord van de server. Als deze tijdslimiet wordt overschreden, zal [fetch] een uitzondering genereren;
- regel 24: om de URL [/main.php?action=init-session&type=json] te verkrijgen, gebruiken we de bibliotheek [qs] om de codering URL te verkrijgen van de parameters [action,type] van de GET. De verkregen tekenreeks is [init-session&type=json], die we ook zelf hadden kunnen samenstellen. We wilden alleen laten zien hoe je een gecodeerde tekenreeks URL kunt verkrijgen;
- regel 24: het sleutelwoord [await] geeft aan dat hier een asynchrone taak wordt gestart en dat we wachten tot deze zijn antwoord publiceert op de gebeurtenislus van [node.js];
- regel 24: in [response] krijgen we een complex object dat het volledige ontvangen antwoord HTTP beschrijft (headers en document);
- regels 30-31: het object [response] wordt weergegeven om de structuur ervan te bekijken, eerst als tekenreeks en vervolgens als JavaScript-object;
- regel 33: we geven de door de server verzonden headers HTTP weer;
- regel 38: we weten dat de belastingberekeningsserver een tekenreeks jSON zal verzenden. Deze is ingekapseld in het object [response]. We kunnen deze ophalen met de methode [response.json()]. Deze methode is echter asynchroon. We schrijven dus [await response.json()] om de tekenreeks jSON te verkrijgen, die zal worden gepubliceerd op de gebeurtenislus van [node.js]. In feite krijgen we niet de tekenreeks jSON, maar het JavaScript-object dat hierdoor wordt vertegenwoordigd;
- regel 39: weergave van de ontvangen tekenreeks jSON;
- regel 40: het ontvangen JavaScript-object wordt geretourneerd;
- regel 47: een eventuele fout in de instructie [fetch] wordt opgevangen. Deze instructie genereert alleen een uitzondering als de bewerking HTTP niet kon worden voltooid en er geen antwoord van de server is ontvangen. Als er een antwoord is ontvangen, zelfs met een HTTP-code die verschilt van [200 OK], genereert [fetch] geen uitzondering en is het antwoord van de server beschikbaar op regel 38;
- regels 51-52: het object [error] dat via de clausule [catch] is ontvangen, wordt weergegeven, eerst als een tekenreeks jSON en vervolgens als een JavaScript-object;
- regel 54: de foutmelding van [fetch] bevindt zich in [error.message];
- regels 59-69: de asynchrone functie [main] roept de asynchrone functie [initSession] op in een blokkerende modus (await op regel 62);
- regel 72: de asynchrone functie [main] wordt gestart en de hoofdcode van het script is dan voltooid. Het totale script is voltooid wanneer de gestarte asynchrone taken hun resultaten op de gebeurtenislus hebben gepubliceerd;
De resultaten van de uitvoering zijn als volgt:
Geval 1: de Laragon-server is niet gestart
[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\http\fetch-01.js"
requête HTTP vers le serveur en cours ---------------------------------------------
error fetch en json={"message":"network timeout at: http://localhost/php7/scripts-web/impots/version-14/main.php?action=init-session&type=json","type":"request-timeout"}, heure=10:08:48:180, durée= 2 seconde(s) et 62 millisecondes
error fetch en javascript= object { FetchError: network timeout at: http://localhost/php7/scripts-web/impots/version-14/main.php?action=init-session&type=json
at Timeout.<anonymous> (c:\Data\st-2019\dev\es6\javascript\node_modules\node-fetch\lib\index.js:1448:13)
at ontimeout (timers.js:436:11)
at tryOnTimeout (timers.js:300:5)
at listOnTimeout (timers.js:263:5)
at Timer.processTimers (timers.js:223:10)
message:
'netwerktime-out op: http://localhost/php7/scripts-web/impots/version-14/main.php?action=init-session&type=json',
type: 'request-timeout' }
erreur ---------------------------------------------
erreur= network timeout at: http://localhost/php7/scripts-web/impots/version-14/main.php?action=init-session&type=json string
[Done] exited with code=0 in 2.804 seconds
Opmerkingen
- regel 3: het verzoek HTTP mislukt na 2 seconden en 62 milliseconden vanwege de time-out van 2 seconden die was opgelegd aan het verzoek HTTP;
- regels 4-9: het JavaScript-object [error] wordt onderschept door de clausule [catch(error)]. Dit object heeft twee eigenschappen:
- [FetchError]: regel 4;
- [message]: regels 10-12;
- regel 14: de foutmelding die is ontvangen door de asynchrone functie [main];
Geval 2: de Laragon-server is gestart
[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\http\fetch-01.js"
requête HTTP vers le serveur en cours ---------------------------------------------
réponse fetch formatée en json,={"size":0,"timeout":2000}, heure=10:13:50:814, durée= 0 seconde(s) et 375 millisecondes
réponse fetch en javascript= Response {
size: 0,
timeout: 2000,
[Symbol(Body internals)]:
{ body:
PassThrough {
_readableState: [ReadableState],
readable: true,
domain: null,
_events: [Object],
_eventsCount: 2,
_maxListeners: undefined,
_writableState: [WritableState],
writable: false,
allowHalfOpen: true,
_transformState: [Object] },
disturbed: false,
error: null },
[Symbol(Response internals)]:
{ url:
'http://localhost/php7/scripts-web/impots/version-14/main.php?action=init-session&type=json',
status: 200,
statusText: 'OK',
headers: Headers { [Symbol(map)]: [Object] },
counter: 0 } }
entêtes de la réponse= Headers {
[Symbol(map)]:
[Object: null prototype] {
date: [ 'Sat, 14 Sep 2019 08:13:50 GMT' ],
server: [ 'Apache/2.4.35 (Win64) OpenSSL/1.1.0i PHP/7.2.11' ],
'x-powered-by': [ 'PHP/7.2.11' ],
'cache-control': [ 'max-age=0, private, must-revalidate, no-cache, private' ],
'set-cookie': [ 'PHPSESSID=99q2iinusmhl55fa600aie2mmu; path=/' ],
'content-length': [ '86' ],
connection: [ 'close' ],
'content-type': [ 'application/json' ] } }
réponse json={"action":"init-session","état":700,"réponse":"session démarrée avec type [json]"}, type=object, heure=10:13:50:825, durée= 0 seconde(s) et 1 millisecondes
succès ---------------------------------------------
réponse= { action: 'init-session',
'status': 700,
''antwoord': 'sessie gestart met type [json]' } object
[Done] exited with code=0 in 1.022 seconds
Opmerkingen
- regel 3: [fetch] ontvangt het antwoord van de server na 375 ms;
- regels 4-39: de structuur van het JavaScript-object [response] waarin het antwoord van de server is ingekapseld. Van de eigenschappen hiervan kunnen sommige voor ons van belang zijn:
- [status] (regel 25): code HTTP van het antwoord van de server;
- [statusText] (regel 26): tekst die bij deze code hoort;
- [headers] (regel 27): de headers HTTP van het serverantwoord;
- [body] (regel 8): vertegenwoordigt het door de server verzonden document. De instructie [fetch] biedt methoden om dit te verwerken;
- regels 29-39: de headers HTTP van het antwoord van de server;
- regel 40: de asynchrone functie [response.json()] heeft haar antwoord na 1 milliseconde gepubliceerd;
- regels 42-44: het JavaScript-object dat door de asynchrone functie [main] wordt ontvangen;
Geval 3: de Laragon-server is gestart, maar er wordt een onjuiste opdracht naar de server gestuurd:

- hierboven, regel 26, wordt een verkeerd sessietype doorgegeven aan de server;
De resultaten van de uitvoering zijn als volgt:
requête HTTP vers le serveur en cours ---------------------------------------------
réponse fetch formatée en json,={"size":0,"timeout":2000}, heure=10:27:54:114, durée= 0 seconde(s) et 136 millisecondes
réponse fetch en javascript= Response {
size: 0,
timeout: 2000,
[Symbol(Body internals)]:
{ body:
PassThrough {
_readableState: [ReadableState],
readable: true,
domain: null,
_events: [Object],
_eventsCount: 2,
_maxListeners: undefined,
_writableState: [WritableState],
writable: false,
allowHalfOpen: true,
_transformState: [Object] },
disturbed: false,
error: null },
[Symbol(Response internals)]:
{ url:
''http://localhost/php7/scripts-web/impots/version-14/main.php?action=init-session&type=x',
status: 400,
statusText: 'Bad Request',
headers: Headers { [Symbol(map)]: [Object] },
counter: 0 } }
entêtes de la réponse= Headers {
[Symbol(map)]:
[Object: null prototype] {
date: [ 'Sat, 14 Sep 2019 08:27:54 GMT' ],
server: [ 'Apache/2.4.35 (Win64) OpenSSL/1.1.0i PHP/7.2.11' ],
'x-powered-by': [ 'PHP/7.2.11' ],
'cache-control': [ 'max-age=0, private, must-revalidate, no-cache, private' ],
'set-cookie': [ 'PHPSESSID=5ku9gfok81ikj98hia0meeum57; path=/' ],
'content-length': [ '79' ],
connection: [ 'close' ],
'content-type': [ 'application/json' ] } }
réponse json={"action":"init-session","état":703,"réponse":"paramètre type=[x] invalide"}, type=object, heure=10:27:54:127, durée= 0 seconde(s) et 2 millisecondes
succès ---------------------------------------------
réponse= { action: 'init-session',
'status': 703,
'antwoord': 'ongeldige parameter type=[x]' } object
[Done] exited with code=0 in 0.712 seconds
- het antwoord van de server wordt ontvangen op regel 2;
- regel 24: we zien dat de code HTTP van het antwoord van de server 400 is, een foutcode. Toch heeft [fetch] geen uitzondering gegenereerd. Zolang [fetch] een antwoord van de server ontvangt, verwerkt het dit en genereert het geen uitzondering;
- regels 41-43: het antwoord dat wordt ontvangen door de asynchrone functie [main];
12.4. script [fetch-02]
Het volgende script is een bewerking van het script [fetch-01], waarbij alle overbodige details zijn verwijderd:
'use strict';
// imports
import fetch from 'node-fetch';
import qs from 'qs';
// URL basis van de belastingberekeningsserver
const baseUrl = 'http://localhost/php7/scripts-web/impots/version-14/main.php?';
// sessie starten
async function initSession() {
// opties van de query HHTP [get /main.php?action=init-session&type=json]
const options = {
method: "GET",
timeout: 2000
};
// uitvoering van de query HTTP [get /main.php?action=init-session&type=json]
const response = await fetch(baseUrl + qs.stringify({
action: 'init-session',
type: 'json'
}), options);
// resultaat ontvangen in jSON
return await response.json();
}
// de functie main voert de asynchrone functie [initSession] uit
async function main() {
try {
console.log("requête HTTP vers le serveur en cours ---------------------------------------------");
const response = await initSession();
console.log("succès ---------------------------------------------");
console.log("réponse=", response)
} catch (error) {
console.log("erreur ---------------------------------------------");
console.log("erreur=", error.message);
}
}
// test
main();
De resultaten van een normale uitvoering:
[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\http\fetch-02.js"
requête HTTP vers le serveur en cours ---------------------------------------------
succès ---------------------------------------------
réponse= { action: 'init-session',
'status': 700,
'antwoord': 'sessie gestart met type [json]' }
[Done] exited with code=0 in 0.56 seconds
De resultaten van een uitvoering met een uitzondering (de Laragon-server wordt gestopt):
[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\http\fetch-02.js"
requête HTTP vers le serveur en cours ---------------------------------------------
erreur ---------------------------------------------
erreur= network timeout at: http://localhost/php7/scripts-web/impots/version-14/main.php?action=init-session&type=json
[Done] exited with code=0 in 2.701 seconds
12.5. script [axios-01]
We nemen hier het script [fetch-01] dat we herschrijven met de bibliotheek [axios]. Ter herinnering: onze interesse in deze bibliotheek is dat deze overdraagbaar is tussen de omgeving [node.js] en die van gangbare browsers. Dit maakt het mogelijk om:
- in fase 1 onze scripts te testen in een [node.js]-omgeving;
- in fase 2 deze naar een browser te porten;
Het script [axios-01] volgt de structuur van het script [fetch-01]:
'use strict';
import axios from 'axios';
// standaardconfiguratie van axios
axios.defaults.timeout = 2000;
axios.defaults.baseURL = 'http://localhost/php7/scripts-web/impots/version-14';
// sessie starten
async function initSession(axios) {
// verzoekopties HHTP [get /main.php?action=init-session&type=json]
const options = {
method: "GET",
// parameters van de URL
params: {
action: 'init-session',
type: 'json'
}
};
// uitvoering van de aanvraag HTTP [get /main.php?action=init-session&type=json]
try {
// asynchroon verzoek
const response = await axios.request('main.php', options);
// het antwoord is het volledige antwoord HTTP van de server (HTTP-headers + het antwoord zelf)
// we geven dit antwoord weer om de structuur ervan te bekijken
console.log("réponse axios=", response);
// het antwoord van de server staat in [response.data]
return response.data;
} catch (error) {
// we zijn hier omdat de server een foutcode heeft verzonden: [404 Not Found, 500 Internal Server Error, ...]
// de parameter [error] is een uitzondering – deze kan verschillende vormen aannemen
// we geven deze weer om de structuur ervan te bekijken
console.log("axios error=", typeof (error), error);
if (error.response) {
// de server heeft een fout gemeld in de status HTTP, maar heeft ook een antwoord verzonden
// en deze is te vinden in [error.response.data]
// we weten dat de server antwoorden jSON verstuurt met de structuur {actie, status, antwoord}
// en dat in geval van een fout het foutbericht in [réponse] staat
return error.response.data;
} else {
// de fout wordt gegenereerd
throw error;
}
}
}
// voert de functie `main` de asynchrone functie [initSession] uit
async function main() {
try {
console.log("requête HTTP vers le serveur en cours ---------------------------------------------");
const response = await initSession(axios);
console.log("succès ---------------------------------------------");
console.log("réponse=", response, typeof (response))
} catch (error) {
console.log("erreur ---------------------------------------------");
console.log("erreur=", error.message);
}
}
// test
main();
Opmerkingen
- regel 2: we importeren de bibliotheek [axios];
- regels 5-6: standaardconfiguratie van de HTTP-verzoeken. De opties van [axios.defaults] gelden voor alle HTTP-verzoeken die door het object [axios] worden verzonden, zonder dat deze bij elk nieuw verzoek opnieuw hoeven te worden opgegeven;
- regel 5: time-out van 2 seconden voor alle verzoeken;
- regel 6: alle URL-verzoeken worden uitgedrukt ten opzichte van het basisverzoek URL;
- regel 9: de asynchrone functie [initSession];
- regels 11-18: de opties van de aanvraag HTTP die zal worden verzonden (naast de standaardopties die al in de regels 5-6 zijn gedefinieerd);
- regels 14-17: de parameters van de URL [action=init-session&type=json]. Het object [params] wordt automatisch omgezet in een gecodeerde tekenreeks URL;
- regel 22: blokkerende aanroep van de asynchrone functie [axios.request]. De eerste parameter is het doelobject URL, opgebouwd uit [main.php] plus het basisobject URL dat in regel 6 is gedefinieerd. De tweede parameter is het object [options] uit de regels 11-18;
- regel 25: [response] is een JavaScript-object dat het volledige antwoord HTTP van de server omvat (headers HTTP + antwoorddocument). Dit wordt weergegeven om de JavaScript-structuur ervan te bekijken;
- regel 27: als de server een document heeft verzonden, dan is dit te vinden in [response.data]. Hier weten we dat de server een antwoord jSON verstuurt, vergezeld van de header HTTP [Content-type : application/json]. Door de aanwezigheid van deze header deserialiseert [axios] automatisch [response.data] naar een JavaScript-object;
- regel 28: de functie [axios] kan een uitzondering genereren. Dit is het punt waarop [axios] verschilt van [fetch]. Er wordt een uitzondering gegenereerd in de volgende gevallen:
- de aanvraag HTTP kon niet worden verzonden (fout aan de kant van de client);
- de server heeft een foutcode HTTP (400, 404, 500, …) teruggestuurd (dit punt is in feite configureerbaar). Ter herinnering: als deze foutcode HTTP vergezeld gaat van een antwoord, veroorzaakte [fetch] geen uitzondering, terwijl [axios] dat wel doet. Als de foutcode HTTP echter vergezeld gaat van een document, wordt dit in [error.response] geplaatst;
- regel 32: de JavaScript-structuur van het object [error] wordt weergegeven;
- regels 33-38: als het object [error] een object [response] bevat, wordt dit antwoord teruggestuurd naar de aanroepende code;
- regels 39-42: in alle andere gevallen wordt het object [error] teruggestuurd naar de aanroepende code;
- regels 47-57: de asynchrone functie [main];
- regel 50: blokkerende aanroep van de asynchrone functie [initSession]. Het antwoord jSON wordt van de server opgehaald als een JavaScript-object;
- regels 53-56: opvangen van een eventuele fout. Het foutbericht bevindt zich in [error.message];
De resultaten van de uitvoering zijn als volgt:
Geval 1: de Laragon-server is niet gestart
[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\http\axios-01.js"
requête HTTP vers le serveur en cours ---------------------------------------------
axios error= object { Error: timeout of 2000ms exceeded
at createError (c:\Data\st-2019\dev\es6\javascript\node_modules\axios\lib\core\createError.js:16:15)
at Timeout.handleRequestTimeout (c:\Data\st-2019\dev\es6\javascript\node_modules\axios\lib\adapters\http.js:252:16)
at ontimeout (timers.js:436:11)
at tryOnTimeout (timers.js:300:5)
at listOnTimeout (timers.js:263:5)
at Timer.processTimers (timers.js:223:10)
config:
{ url:
'http://localhost/php7/scripts-web/impots/version-14/main.php',
method: 'get',
params: { action: 'init-session', type: 'json' },
headers:
{ Accept: 'application/json, text/plain, */*',
'User-Agent': 'axios/0.19.0' },
baseURL: 'http://localhost/php7/scripts-web/impots/version-14',
transformRequest: [ [Function: transformRequest] ],
transformResponse: [ [Function: transformResponse] ],
timeout: 2000,
adapter: [Function: httpAdapter],
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
validateStatus: [Function: validateStatus],
data: undefined },
code: 'ECONNABORTED',
request:
Writable {
_writableState:
WritableState {
objectMode: false,
highWaterMark: 16384,
finalCalled: false,
needDrain: false,
ending: false,
ended: false,
finished: false,
destroyed: false,
decodeStrings: true,
defaultEncoding: 'utf8',
length: 0,
writing: false,
corked: 0,
sync: true,
bufferProcessing: false,
onwrite: [Function: bound onwrite],
writecb: null,
writelen: 0,
bufferedRequest: null,
lastBufferedRequest: null,
pendingcb: 0,
prefinished: false,
errorEmitted: false,
emitClose: true,
bufferedRequestCount: 0,
corkedRequestsFree: [Object] },
writable: true,
domain: null,
_events:
[Object: null prototype] {
response: [Function: handleResponse],
error: [Function: handleRequestError] },
_eventsCount: 2,
_maxListeners: undefined,
_options:
{ protocol: 'http:',
maxRedirects: 21,
maxBodyLength: 10485760,
path:
'/php7/scripts-web/impots/version-14/main.php?action=init-session&type=json',
method: 'GET',
headers: [Object],
agent: undefined,
auth: undefined,
hostname: 'localhost',
port: null,
nativeProtocols: [Object],
pathname: '/php7/scripts-web/impots/version-14/main.php',
search: '?action=init-session&type=json' },
_redirectCount: 0,
_redirects: [],
_requestBodyLength: 0,
_requestBodyBuffers: [],
_onNativeResponse: [Function],
_currentRequest:
ClientRequest {
domain: null,
_events: [Object],
_eventsCount: 6,
_maxListeners: undefined,
output: [],
outputEncodings: [],
outputCallbacks: [],
outputSize: 0,
writable: true,
_last: true,
chunkedEncoding: false,
shouldKeepAlive: false,
useChunkedEncodingByDefault: false,
sendDate: false,
_removedConnection: false,
_removedContLen: false,
_removedTE: false,
_contentLength: 0,
_hasBody: true,
_trailer: '',
finished: true,
_headerSent: true,
socket: [Socket],
connection: [Socket],
_header:
'GET /php7/scripts-web/impots/version-14/main.php?action=init-session&type=json HTTP/1.1\r\nAccept: application/json, text/plain, */*\r\nUser-Agent: axios/0.19.0\r\nHost: localhost\r\nConnection: close\r\n\r\n',
_onPendingData: [Function: noopPendingOutput],
agent: [Agent],
socketPath: undefined,
timeout: undefined,
method: 'GET',
path:
'/php7/scripts-web/impots/version-14/main.php?action=init-session&type=json',
_ended: false,
res: null,
aborted: 1568528450762,
timeoutCb: null,
upgradeOrConnect: false,
parser: [HTTPParser],
maxHeadersCount: null,
_redirectable: [Circular],
[Symbol(isCorked)]: false,
[Symbol(outHeadersKey)]: [Object] },
_currentUrl:
'http://localhost/php7/scripts-web/impots/version-14/main.php?action=init-session&type=json' },
response: undefined,
isAxiosError: true,
toJSON: [Function] }
erreur ---------------------------------------------
erreur= timeout of 2000ms exceeded
[Done] exited with code=0 in 2.784 seconds
Opmerkingen
- regels 33-136: het object [error] bevat veel informatie;
- [Error], regels 3-9: een beschrijving van de fout die is opgetreden;
- [config], regels 10-27: de configuratie van de aanvraag HTTP die tot deze fout heeft geleid;
- [config.url], regels 11-12: het doel van URL;
- [config.method], regel 13: de methode van de query;
- [config.params], regel 14: de parameters van URL;
- [config.headers], regels 16-17: de HTTP-headers van de aanvraag;
- [config.baseURL], regel 18: de basis-URL van de doel-URL;
- [config.timeout], regel 21: de time-out van het verzoek;
- [code], regel 28: een foutcode;
- [request], regels 29-133: een gedetailleerde beschrijving van het verzoek HTTP. Opvallend is dat de meeste eigenschappen worden voorafgegaan door het onderstrepingsteken _, wat aangeeft dat het interne eigenschappen van het object [request] betreft die niet bedoeld zijn om rechtstreeks door de ontwikkelaar te worden gebruikt;
- [response], regel 134: het antwoord van de server, dat hier ontbreekt;
- regel 138: de foutmelding die wordt weergegeven door de functie [main];
Geval 2: de Laragon-server is gestart
[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\http\axios-01.js"
requête HTTP vers le serveur en cours ---------------------------------------------
réponse axios= { status: 200,
statusText: 'OK',
headers:
{ date: 'Sun, 15 Sep 2019 07:09:26 GMT',
server: 'Apache/2.4.35 (Win64) OpenSSL/1.1.0i PHP/7.2.11',
'x-powered-by': 'PHP/7.2.11',
'cache-control': 'max-age=0, private, must-revalidate, no-cache, private',
'set-cookie': [ 'PHPSESSID=uas6lugtblstktcifpd8e5irm6; path=/' ],
'content-length': '86',
connection: 'close',
'content-type': 'application/json' },
config:
{ url:
'`http://localhost/php7/scripts-web/impots/version-14/main.php'',
method: 'get',
params: { action: 'init-session', type: 'json' },
headers:
{ Accept: 'application/json, text/plain, */*',
''User-Agent': 'axios/0.19.0' },
baseURL: 'http://localhost/php7/scripts-web/impots/version-14',
transformRequest: [ [Function: transformRequest] ],
transformResponse: [ [Function: transformResponse] ],
timeout: 2000,
adapter: [Function: httpAdapter],
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
validateStatus: [Function: validateStatus],
data: undefined },
request:
ClientRequest {
domain: null,
_events:
[Object: null prototype] {
socket: [Function],
abort: [Function],
aborted: [Function],
error: [Function],
timeout: [Function],
prefinish: [Function: requestOnPrefinish] },
_eventsCount: 6,
_maxListeners: undefined,
output: [],
outputEncodings: [],
outputCallbacks: [],
outputSize: 0,
writable: true,
_last: true,
chunkedEncoding: false,
shouldKeepAlive: false,
useChunkedEncodingByDefault: false,
sendDate: false,
_removedConnection: false,
_removedContLen: false,
_removedTE: false,
_contentLength: 0,
_hasBody: true,
_trailer: '',
finished: true,
_headerSent: true,
socket:
Socket {
connecting: false,
_hadError: false,
_handle: [TCP],
_parent: null,
_host: 'localhost',
_readableState: [ReadableState],
readable: true,
domain: null,
_events: [Object],
_eventsCount: 7,
_maxListeners: undefined,
_writableState: [WritableState],
writable: false,
allowHalfOpen: false,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: null,
_server: null,
parser: null,
_httpMessage: [Circular],
[Symbol(asyncId)]: 6,
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]: null,
[Symbol(kBytesRead)]: 0,
[Symbol(kBytesWritten)]: 0 },
connection:
Socket {
connecting: false,
_hadError: false,
_handle: [TCP],
_parent: null,
_host: 'localhost',
_readableState: [ReadableState],
readable: true,
domain: null,
_events: [Object],
_eventsCount: 7,
_maxListeners: undefined,
_writableState: [WritableState],
writable: false,
allowHalfOpen: false,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: null,
_server: null,
parser: null,
_httpMessage: [Circular],
[Symbol(asyncId)]: 6,
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]: null,
[Symbol(kBytesRead)]: 0,
[Symbol(kBytesWritten)]: 0 },
_header:
'GET /php7/scripts-web/impots/version-14/main.php?action=init-session&type=json HTTP/1.1\r\nAccept: application/json, text/plain, */*\r\nUser-Agent: axios/0.19.0\r\nHost: localhost\r\nConnection: close\r\n\r\n',
_onPendingData: [Function: noopPendingOutput],
agent:
Agent {
domain: null,
_events: [Object],
_eventsCount: 1,
_maxListeners: undefined,
defaultPort: 80,
protocol: 'http:',
options: [Object],
requests: {},
sockets: [Object],
freeSockets: {},
keepAliveMsecs: 1000,
keepAlive: false,
maxSockets: Infinity,
maxFreeSockets: 256 },
socketPath: undefined,
timeout: undefined,
method: 'GET',
path:
'/php7/scripts-web/impots/version-14/main.php?action=init-session&type=json',
_ended: true,
res:
IncomingMessage {
_readableState: [ReadableState],
readable: false,
domain: null,
_events: [Object],
_eventsCount: 3,
_maxListeners: undefined,
socket: [Socket],
connection: [Socket],
httpVersionMajor: 1,
httpVersionMinor: 0,
httpVersion: '1.0',
complete: true,
headers: [Object],
rawHeaders: [Array],
trailers: {},
rawTrailers: [],
aborted: false,
upgrade: false,
url: '',
method: null,
statusCode: 200,
statusMessage: 'OK',
client: [Socket],
_consuming: false,
_dumped: false,
req: [Circular],
responseUrl:
'http://localhost/php7/scripts-web/impots/version-14/main.php?action=init-session&type=json',
redirects: [] },
aborted: undefined,
timeoutCb: null,
upgradeOrConnect: false,
parser: null,
maxHeadersCount: null,
_redirectable:
Writable {
_writableState: [WritableState],
writable: true,
domain: null,
_events: [Object],
_eventsCount: 2,
_maxListeners: undefined,
_options: [Object],
_redirectCount: 0,
_redirects: [],
_requestBodyLength: 0,
_requestBodyBuffers: [],
_onNativeResponse: [Function],
_currentRequest: [Circular],
_currentUrl:
'http://localhost/php7/scripts-web/impots/version-14/main.php?action=init-session&type=json' },
[Symbol(isCorked)]: false,
[Symbol(outHeadersKey)]:
[Object: null prototype] { accept: [Array], 'user-agent': [Array], host: [Array] } },
data:
{ action: 'init-session',
'status': 700,
'antwoord': 'sessie gestart met type [json]' } }
succès ---------------------------------------------
réponse= { action: 'init-session',
'status': 700,
'antwoord': 'sessie gestart met type [json]' } object
[Done] exited with code=0 in 1.115 seconds
Opmerkingen
- regels 3-203: het JavaScript-object [response] dat het antwoord HTTP van de server omvat;
- regel 3, [status]: de code HTTP van het antwoord;
- regel 4, [statusText]: de tekst die hoort bij de voorgaande code HTTP;
- regels 5-13, [headers]: de headers HTTP van het antwoord:
- regel 10, [Set-Cookie]: de sessiecookie;
- regel 13, [Content-Type]: het type document dat door de server is verzonden;
- regels 14-31, [config]: de configuratie van het verzonden verzoek HTTP;
- regels 32-199, [request]: het JavaScript-object met details over het verzonden verzoek HTTP;
- regels 200-203, [request.data]: het JavaScript-object dat het antwoord jSON van de server omvat;
- regels 205-207: het antwoord dat is opgehaald door de asynchrone functie [main];
Geval 3: er wordt een foutieve aanvraag [init-session] naar de Laragon-server verzonden;

De resultaten van de uitvoering zijn als volgt:
[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\http\axios-01.js"
requête HTTP vers le serveur en cours ---------------------------------------------
axios error= object { Error: Request failed with status code 400
...
config:
{ url:
''http://localhost/php7/scripts-web/impots/version-14/main.php',
...
data: undefined },
request:
...
[Symbol(outHeadersKey)]:
[Object: null prototype] { accept: [Array], 'user-agent': [Array], host: [Array] } },
response:
{ status: 400,
statusText: 'Bad Request',
headers:
{ date: 'Sun, 15 Sep 2019 07:25:58 GMT',
server: 'Apache/2.4.35 (Win64) OpenSSL/1.1.0i PHP/7.2.11',
'x-powered-by': 'PHP/7.2.11',
'cache-control': 'max-age=0, private, must-revalidate, no-cache, private',
'set-cookie': [Array],
'content-length': '79',
connection: 'close',
'content-type': 'application/json' },
config:
{ url:
'`http://localhost/php7/scripts-web/impots/version-14/main.php'',
...
data: undefined },
request:
...
[Symbol(outHeadersKey)]: [Object] },
data:
{ action: 'init-session',
'status': 703,
'antwoord': 'ongeldige parameter type=[x]' } },
isAxiosError: true,
toJSON: [Function] }
succès ---------------------------------------------
réponse= { action: 'init-session',
'status': 703,
'antwoord': 'ongeldige parameter type=[x]' } object
[Done] exited with code=0 in 0.69 seconds
Omdat de server met een 400-code (regel 15) heeft gereageerd, heeft HTTP een uitzondering gegenereerd (ook dit gedrag is configureerbaar). Hoewel [axios] een uitzondering heeft gegenereerd, krijgen we in [error.response] (regel 14) wel het antwoord HTTP van de server en wordt het document jSON verzonden naar [error.response.data] (regel 34). Regels 41-43: de functie [main] haalt het antwoord jSON correct op van de server.
12.6. script [axios-02]
Nu we de objecten hebben beschreven die door de bibliotheek [axios] worden verwerkt tijdens een verzoek HTTP, kunnen we het script [axios-01] als volgt herschrijven:
''use strict';
import axios from 'axios';
// standaardconfiguratie van axios
axios.defaults.timeout = 2000;
axios.defaults.baseURL = 'http://localhost/php7/scripts-web/impots/version-14';
// sessie initialiseren
async function initSession(axios) {
// verzoekopties HHTP [get /main.php?action=init-session&type=json]
const options = {
method: "GET",
// parameters van de URL
params: {
action: 'init-session',
type: 'json'
}
};
try {
// uitvoering van de aanvraag HTTP [get /main.php?action=init-session&type=json]
const response = await axios.request('main.php', options);
// het antwoord van de server staat in [response.data]
return response.data;
} catch (error) {
// antwoord van de server
if (error.response) {
// het antwoord jSON staat in [error.response.data]
return error.response.data;
} else {
// de fout wordt opnieuw gegenereerd
throw error;
}
}
}
// de functie main voert de asynchrone functie [initSession] uit
async function main() {
try {
console.log("requête HTTP vers le serveur en cours ---------------------------------------------");
const response = await initSession(axios);
console.log("succès ---------------------------------------------");
console.log("réponse=", response, typeof (response))
} catch (error) {
console.log("erreur ---------------------------------------------");
console.log("erreur=", error.message);
}
}
// test
main();
12.7. script [axios-03]
Het script [axios-03] volgt dezelfde werkwijze als het script [axios-02]. Deze keer voegen we de aanvraag HTTP [authentifier-utilisateur] toe aan de server, wat gebeurt met behulp van een POST:
'use strict';
import axios from 'axios';
import qs from 'qs'
// axios-configuratie
axios.defaults.timeout = 2000;
axios.defaults.baseURL = 'http://localhost/php7/scripts-web/impots/versie-14';
// sessie starten
async function initSession(axios) {
// verzoekopties HHTP [get /main.php?action=init-session&type=json]
const options = {
method: "GET",
// parameters van de URL
params: {
action: 'init-session',
type: 'json'
}
};
try {
// uitvoering van de aanvraag HTTP [get /main.php?action=init-session&type=json]
const response = await axios.request('main.php', options);
// het antwoord van de server staat in [response.data]
return response.data;
} catch (error) {
// antwoord van de server
if (error.response) {
// het antwoord jSON staat in [error.response.data]
return error.response.data;
} else {
// de fout wordt opnieuw gegenereerd
throw error;
}
}
}
async function authentifierUtilisateur(axios, user, password) {
// verzoekopties HHTP [POST /main.php?action=authentifier-utilisateur]
const options = {
method: "POST",
headers: {
'Content-type': 'application/x-www-form-urlencoded',
},
// hoofdtekst van het POST
data: qs.stringify({
user: user,
password: password
}),
// parameters van de URL
params: {
action: 'authentifier-utilisateur'
}
};
try {
// uitvoering van de aanvraag HTTP [post /main.php?action=authentifier-utilisateur]
const response = await axios.request('main.php', options);
// het antwoord van de server staat in [response.data]
return response.data;
} catch (error) {
// antwoord van de server
if (error.response) {
// het antwoord jSON staat in [error.response.data]
return error.response.data;
} else {
// de fout wordt opnieuw gegenereerd
throw error;
}
}
}
// de functie `main` voert de asynchrone functies één voor één uit
async function main() {
try {
// init-session
console.log("action init-session en cours ---------------------------------------------");
const response1 = await initSession(axios);
console.log("succès ---------------------------------------------");
console.log("réponse=", response1);
// gebruikersauthenticatie
console.log("action authentifier-utilisateur en cours ---------------------------------------------");
const response2 = await authentifierUtilisateur(axios, 'admin', 'admin');
console.log("succès ---------------------------------------------");
console.log("réponse=", response2)
} catch (error) {
console.log("erreur ---------------------------------------------");
console.log("erreur=", error);
}
}
// test
main();
Opmerkingen
- regels 38-70: de asynchrone functie [authentifierUtilisateur];
- regel 39: de aanvraag [POST /main.php?action=authentifier-utilisateur] moet worden uitgevoerd;
- regels 40-54: de opties van de aanvraag HTTP;
- regel 41: dit is een POST;
- regels 42-44: de parameters van de POST worden gecodeerd in een document dat de klant samen met zijn verzoek verstuurt;
- regels 46-49: de eigenschap [data] moet de gecodeerde tekenreeks van POST URL bevatten. Hiervoor wordt de bibliotheek [qs] gebruikt, die in regel 3 is geïmporteerd;
- regels 55-69: voor de uitvoering van de query wordt dezelfde code gebruikt als in de methode [initSession];
- regels 73-89: de methode [asynchrone] roept achtereenvolgens, op blokkerende wijze, de methoden [initSession, authentifierUtilisateur] aan, regels 77 en 82;
- regel 82: het paar (admin, admin) wordt gebruikt als inloggegevens. We weten dat deze door de server worden herkend;
De resultaten van de uitvoering zijn als volgt:
[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\http\axios-03.js"
action init-session en cours ---------------------------------------------
succès ---------------------------------------------
réponse= { action: 'init-session',
'status': 700,
'antwoord': 'sessie gestart met type [json]' }
action authentifier-utilisateur en cours ---------------------------------------------
succès ---------------------------------------------
réponse= { action: 'authentifier-utilisateur',
'status': 103,
'antwoord':
[ 'pas de session en cours. Commencer par action [init-session]' ] }
[Done] exited with code=0 in 0.834 seconds
- regels 9-12: de gebruikersauthenticatie mislukt: de server heeft niet onthouden dat er een sessie jSON was gestart. Dit komt doordat de sessiecookie die als antwoord op het eerste verzoek [init-session] werd verzonden, niet is teruggestuurd;
12.8. script [axios-04]
Het script [axios-04] brengt twee verbeteringen aan in het script [axios-03]:
- het beheert de sessiecookie;
- het fasceert in een functie [getRemoteData] wat gemeenschappelijk is aan de functies [initSession] en [authentifierUtilisateur];
'use strict';
import axios from 'axios';
import qs from 'qs'
// axios-configuratie
axios.defaults.timeout = 2000;
axios.defaults.baseURL = 'http://localhost/php7/scripts-web/impots/version-14';
// sessiecookie
const sessionCookieName = "PHPSESSID";
let sessionCookie = '';
// sessie starten
async function initSession(axios) {
// verzoekopties HHTP [get /main.php?action=init-session&type=json]
const options = {
method: "GET",
// parameters van de URL
params: {
action: 'init-session',
type: 'json'
}
};
// uitvoering van de query HTTP
return await getRemoteData(axios, options);
}
async function authentifierUtilisateur(axios, user, password) {
// opties van de aanvraag HHTP [post /main.php?action=authentifier-utilisateur]
const options = {
method: "POST",
headers: {
'Content-type': 'application/x-www-form-urlencoded',
},
// hoofdtekst van het POST
data: qs.stringify({
user: user,
password: password
}),
// parameters van de URL
params: {
action: 'authentifier-utilisateur'
}
};
// uitvoering van de aanvraag HTTP
return await getRemoteData(axios, options);
}
async function getRemoteData(axios, options) {
// voor de sessiecookie
if (!options.headers) {
options.headers = {};
}
options.headers.Cookie = sessionCookie;
// uitvoering van de verzoek HTTP
let response;
try {
// asynchrone verzoek
response = await axios.request('main.php', options);
} catch (error) {
// de parameter [error] is een uitzondering – deze kan verschillende vormen aannemen
if (error.response) {
// het antwoord van de server staat in [error.response]
response = error.response;
} else {
// de fout wordt opnieuw gegenereerd
throw error;
}
}
// response is het volledige antwoord HTTP van de server (headers HTTP + het antwoord zelf)
// de sessiecookie wordt opgehaald, indien deze bestaat
const setCookie = response.headers['set-cookie'];
if (setCookie) {
// setCookie is een array
// we zoeken de sessiecookie in deze array
let trouvé = false;
let i = 0;
while (!trouvé && i < setCookie.length) {
// we zoeken naar de sessiecookie
const results = RegExp('^(' + sessionCookieName + '.+?);').exec(setCookie[i]);
if (results) {
// de sessiecookie wordt opgeslagen
// eslint-disable-next-line require-atomic-updates
sessionCookie = results[1];
// gevonden
trouvé = true;
} else {
// volgend element
i++;
}
}
}
// het antwoord van de server staat in [response.data]
return response.data;
}
// de functie main voert de asynchrone functies één voor één uit
async function main() {
try {
// init-session
console.log("action init-session en cours ---------------------------------------------");
const response1 = await initSession(axios);
console.log("succès ---------------------------------------------");
console.log("réponse=", response1);
// gebruikersauthenticatie
console.log("action authentifier-utilisateur en cours ---------------------------------------------");
const response2 = await authentifierUtilisateur(axios, 'admin', 'admin');
console.log("succès ---------------------------------------------");
console.log("réponse=", response2)
} catch (error) {
console.log("erreur ---------------------------------------------");
console.log("erreur=", error.message);
}
}
// test
main();
Opmerkingen
- regels 14-26: de functie [initSession]. Deze functie beperkt zich voortaan tot het voorbereiden van de aanvraag HTTP die naar de server moet worden verzonden, maar voert deze niet uit. Deze taak wordt overgelaten aan de methode [getRemoteDate] in de regels 49-95;
- regels 28-47: de functie [authentifierUtilisateur] volgt dezelfde procedure;
- regel 49: de functie [getRemoteData] ontvangt de twee gegevens waarmee zij een verzoek HTTP kan uitvoeren:
- [axios], het object dat verantwoordelijk is voor het verzenden van de aanvraag en het ontvangen van het antwoord;
- [options], de configuratieopties van de aanvraag die naar de server moet worden verzonden;
- regel 59: uitvoering van de aanvraag en blokkerend wachten op het antwoord jSON;
- regels 60-68: afhandeling van een eventuele uitzondering;
- regel 64: het antwoord wordt opgehaald, dat in het foutobject kan zijn ingekapseld;
- regel 67: als de server een uitzondering heeft gegenereerd zonder het antwoord van de server mee te sturen, wordt de ontvangen fout doorgegeven aan de aanroepende code;
- de functie [getRemoteData] beheert de sessiecookie:
- hij slaat deze op in de variabele [sessionCookie] (regel 11) wanneer hij deze voor het eerst ontvangt;
- vervolgens stuurt hij deze bij elk nieuw verzoek terug als HTTP;
- regels 72-92: [getRemoteData] analyseert elk antwoord van de server om te controleren of deze de header HTTP [Set-Cookie] heeft verzonden. We weten dat de server een sessiecookie met de naam [PHPSESSID] verstuurt (regel 10). Het is dus deze cookie waarnaar wordt gezocht (regel 10);
- regel 72: we halen de headers HTTP en [Set-Cookie] op, indien deze aanwezig zijn (hoofdlettergebruik maakt niet uit). Er kunnen namelijk meerdere headers [Set-Cookie] zijn en daarom wordt er een array opgehaald;
- regel 73: als er een array met cookies is opgehaald;
- regels 78-90: we zoeken de sessiecookie tussen alle cookies in de array;
- regel 80: de relationele uitdrukking waarmee de sessiecookie in cookie nr. i kan worden gezocht;
- regel 81: als de vergelijking resultaten heeft opgeleverd;
- regel 84: in results[1] hebben we het eerste deel van de relationele uitdrukking, d.w.z. (PHPSESSID=xxxx) tot aan de punt (niet inbegrepen) die de sessiecookie afsluit;
- regels 50-54: bij elk verzoek wordt de sessiecookie opgenomen in de headers HTTP van het verzoek. De eerste keer is deze cookie leeg en wordt hij dus door de server genegeerd;
De resultaten van de uitvoering zijn als volgt:
[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\http\axios-04.js"
action init-session en cours ---------------------------------------------
succès ---------------------------------------------
réponse= { action: 'init-session',
'status': 700,
'antwoord': 'sessie gestart met type [json]' }
action authentifier-utilisateur en cours ---------------------------------------------
succès ---------------------------------------------
réponse= { action: 'authentifier-utilisateur',
'status': 200,
'antwoord': 'Authenticatie geslaagd [admin, admin]' }
[Done] exited with code=0 in 0.982 seconds