12. As funções HTTP em JavaScript

12.1. Escolha de uma biblioteca HTTP
Neste caso, optámos por duas bibliotecas:
O EcmaScript 6 possui, de forma nativa, uma função HTTP denominada [fetch], que não está implementada pelo [node.js] (setembro de 2019). Existe uma biblioteca denominada [node-fetch] que permite utilizar a função [fetch] no Node. Esta biblioteca utiliza certas API específicas do [node.js]. Um código [node-fetch] pode, portanto, não ser 100 % transportável para um ambiente que não seja [node], por exemplo, num navegador;
Existe, além disso, uma biblioteca denominada [axios] dedicada a requisições HTTP, compatível tanto com o [node.js] como com os navegadores. É esta biblioteca que acabaremos por utilizar.
Vamos apresentar um mesmo script escrito com estas duas bibliotecas para mostrar que o processo de codificação com elas é semelhante.
12.2. Configuração de um ambiente de trabalho
12.2.1. Instalação do servidor de cálculo de impostos
Por fim, iremos escrever uma aplicação web com a seguinte arquitetura:

JS: JavaScript
O código JavaScript é do lado do cliente:
- de um serviço de páginas ou fragmentos estáticos;
- de um serviço jSON;
O código JavaScript é, portanto, um cliente jSON e, como tal, pode ser organizado em camadas [UI, métier, dao] (UI: Interface do Utilizador), tal como os nossos clientes jSON escritos em PHP.
O servidor será o do cálculo do imposto, do qual já escrevemos 13 versões. Vamos escrever uma 14.ª. Começamos, portanto, por duplicar, no NetBeans, a pasta da versão 13, na pasta da versão 14:

- em [6], alteramos o ficheiro [config.json] da versão 14 da seguinte forma:
{
"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"
}
- na linha 3, alteramos a pasta raiz da aplicação;
Para aceder a este servidor, é necessário iniciar os serviços [Laragon].
Feito isto, podemos testar com o [Postman] (ver artigo no link), esta nova versão do servidor, idêntica, por enquanto, à versão 13. Podemos utilizar o conjunto de consultas utilizado para testar a versão 12 do servidor de cálculo de impostos:

- em [1-4], utilizar a consulta [init-session-700] para iniciar uma sessão jSON;
- em [4-5], substituir [version-12] por [version-14] para testar a versão 14 do projeto;
- durante a execução, devemos receber a resposta jS0N [6] do servidor;
A versão 14 do servidor está agora operacional. Teremos de a modificar ligeiramente. Recordemos o API deste servidor:
Ação | Função | Contexto de execução |
init-session | Serve para definir o tipo (json, xml, html) das respostas pretendidas | Pedido GET main.php?action=init-session&type=x pode ser enviada a qualquer momento |
autenticar-utilizador | Autoriza ou não um utilizador a iniciar sessão | Pedido POST main.php?action=autenticar-utilizador A solicitação deve ter dois parâmetros enviados via POST [user, password] Só pode ser emitida se o tipo de sessão (json, xml, html) for conhecido |
calcular-imposto | Efetua uma simulação de cálculo de impostos | Pedido POST main.php?action=calculer-impot A solicitação deve ter três parâmetros enviados via POST: [marié, enfants, salaire] Só pode ser emitida se o tipo de sessão (json, xml, html) for conhecido e o utilizador estiver autenticado |
lister-simulações | Solicita a visualização da lista de simulações realizadas desde o início da sessão | Pedido GET main.php?action=lister-simulations A solicitação não aceita nenhum outro parâmetro Só pode ser emitida se o tipo da sessão (json, xml, html) for conhecido e o utilizador estiver autenticado |
eliminar-simulação | Elimina uma simulação da lista de simulações | Consulta GET main.php?action=lister-simulações&número=x A solicitação não aceita nenhum outro parâmetro Só pode ser enviada se o tipo da sessão (json, xml, html) for conhecido e o utilizador estiver autenticado |
fim-sessão | Encerra a sessão de simulações. | Tecnicamente, a sessão web anterior é eliminada e é criada uma nova sessão Só pode ser emitida se o tipo da sessão (json, xml, html) for conhecido e o utilizador estiver autenticado |
12.2.2. Instalação das bibliotecas HTTP do cliente JavaScript
Numa primeira fase, iremos trabalhar com a seguinte arquitetura:

- em [1], um script de consola [node.js] efetua uma solicitação HTTP ao servidor jSON de cálculo do imposto;
- em [4], recebe essa resposta e apresenta-a na consola;
No exemplo n.º 1, utilizaremos as bibliotecas [node-fetch] e [axios] e, posteriormente, manteremos apenas a [axios] para os exemplos seguintes. Vamos agora instalar estas duas bibliotecas JavaScript a partir do terminal de [VSCode]:

Iremos também utilizar a biblioteca [qs], que permite a codificação URL de uma cadeia de caracteres. Recorde-se que esta codificação é utilizada para codificar os parâmetros de um pedido HTTP, GET ou POST.

12.3. script [fetch-01]
O script [fetch-01] utiliza a biblioteca [node-fetch] para inicializar uma sessão jSON com o servidor de cálculo de impostos. O seu código é o seguinte:
'use strict';
// importações
import fetch from 'node-fetch';
import qs from 'qs';
import { sprintf } from 'sprintf-js';
import moment from 'moment';
// URL base do servidor de cálculo de impostos
const baseUrl = 'http://localhost/php7/scripts-web/impostos/versão-14/main.php?';
// inicialização da sessão
async function initSession() {
// opções da consulta HHTP [get /main.php?action=init-session&type=json]
const options = {
method: "GET",
timeout: 2000
};
// execução da consulta HTTP [get /main.php?action=init-session&type=json]
let débutFetch;
try {
// pedido assíncrono — [fetch] devolve uma promessa
débutFetch = moment(Date.now());
const response = await fetch(baseUrl + qs.stringify({
action: 'init-session',
type: 'json'
}), options);
// [response] é a resposta completa do servidor HTTP (cabeçalhos HTTP + a própria resposta)
// esta resposta é apresentada para ver a sua estrutura
console.log(sprintf("réponse fetch formatée en json,=%j, %s", response, heure(débutFetch)));
console.log("réponse fetch en javascript=", response);
// é possível aceder aos cabeçalhos HTTP
console.log("entêtes de la réponse=", response.headers);
// se a resposta for do tipo application/json, a resposta JSON do servidor é obtida com a função assíncrona [response.json()]
// neste caso, o código chamador obtém um objeto [Promise]
// [await] permite obter a resposta [json] do servidor, em vez da sua promessa
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;
// se a resposta for do tipo text/plain, a resposta de texto do servidor é obtida com [response.text()]
// neste caso, o código chamador obtém um objeto [Promise]
// [await] permite obter a resposta [texte] do servidor, em vez da sua promessa
// const text = await response.text();
// console.log("resposta de texto=", texto);
// return text;
} catch (error) {
// estamos aqui porque o servidor enviou um código de erro [404 Not Found, ...] acompanhado de um corpo vazio — exibimos o erro para ver a sua estrutura
// ou porque o cliente [fetch] lançou uma exceção (rede inacessível, ...)
// é apresentada a estrutura do erro
console.log(sprintf("error fetch en json=%j, %s", error, heure(débutFetch)));
console.log("error fetch en javascript=", typeof (error), error);
// lança-se a mensagem de erro recebida
throw error.message;
}
}
// a função main executa a função assíncrona [initSession]
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));
}
}
// teste
main();
// utilitário de exibição da hora e da duração
function heure(début) {
// hora atual
const now = moment(Date.now());
// formatação da hora
let result = "heure=" + now.format("HH:mm:ss:SSS");
// é necessário calcular uma duração?
if (début) {
const durée = now - début;
const milliseconds = durée % 1000;
const seconds = Math.floor(durée / 1000);
// formatação da hora + duração
result = result + sprintf(", durée= %s seconde(s) et %s millisecondes", seconds, milliseconds);
}
// resultado
return result;
}
Comentários
- as funções HTTP do JavaScript são funções assíncronas. Aqui, aplicamos o que aprendemos na secção anterior (ver link);
- linha 24: para aguardar que a resposta da função assíncrona [fetch] seja publicada no ciclo de eventos de [node.js], utilizamos a palavra-chave [await]. Sabemos que esta instrução deve constar num código precedido pela palavra-chave [async] (linha 13);
- linhas 13-56: encapsulamos o código HTTP na função assíncrona [initSession];
- linhas 59-69: uma segunda função assíncrona [main] é utilizada para chamar de forma bloqueante (async/await) a função assíncrona [initSession];
- linha 72: a função assíncrona [main] é chamada;
- embora todo o código se pareça com código síncrono, são, de facto, funções assíncronas que estão a ser executadas, mas de forma bloqueante;
- linha 19: para inicializar uma sessão jSON com o servidor de cálculo de impostos, é necessário enviar-lhe o comando HTTP [get /main.php?action=init-session&type=json]. É isso que o código das linhas 24-27 faz. A sintaxe de [fetch] é a seguinte: [fetch(URL, options)] com:
- [URL]: a consulta URL;
- [options]: um objeto que define as opções da consulta. É aqui, nomeadamente, que se definem os cabeçalhos HTTP que se pretende enviar para a máquina de destino;
- linhas 15-18: definem-se as opções da solicitação que se pretende efetuar:
- [method]: pretende-se efetuar um GET;
- [timeout]: pretende-se que o cliente [fetch] não aguarde mais de 2 segundos pela resposta do servidor. Se este prazo for excedido, o [fetch] lançará uma exceção;
- linha 24: para obter o URL [/main.php?action=init-session&type=json], utiliza-se a biblioteca [qs] para obter a codificação URL dos parâmetros [action,type] do GET. A cadeia obtida é [init-session&type=json], que poderíamos ter construído nós próprios. Queríamos simplesmente mostrar como obter uma cadeia URL codificada;
- linha 24: a palavra-chave [await] indica que aqui é iniciada uma tarefa assíncrona e que se aguarda que esta publique a sua resposta no ciclo de eventos de [node.js];
- linha 24: em [response], obtém-se um objeto complexo que descreve a totalidade da resposta HTTP recebida (cabeçalhos e documento);
- linhas 30-31: exibe-se o objeto [response] para ver a sua estrutura, primeiro como cadeia de caracteres e depois como objeto JavaScript;
- linha 33: exibem-se os cabeçalhos HTTP enviados pelo servidor;
- linha 38: sabemos que o servidor de cálculo de impostos irá enviar uma cadeia jSON. Esta está encapsulada no objeto [response]. É possível obtê-la com o método [response.json()]. No entanto, este método é assíncrono. Escrevemos, portanto, [await response.json()] para obter a cadeia jSON, que será publicada no ciclo de eventos de [node.js]. Na verdade, não é a cadeia jSON que se obtém, mas sim o objeto JavaScript representado por ela;
- linha 39: exibição da cadeia jSON recebida;
- linha 40: devolve-se o objeto JavaScript recebido;
- linha 47: intercepta-se um eventual erro da instrução [fetch]. Esta só lança uma exceção se a operação HTTP não tiver sido bem-sucedida e não tiver sido recebida qualquer resposta do servidor. Se tiver sido recebida uma resposta, mesmo com um código HTTP diferente de [200 OK], [fetch] não lança uma exceção e a resposta do servidor estará disponível na linha 38;
- linhas 51-52: é exibido o objeto [error] recebido pela cláusula [catch], primeiro como uma cadeia de caracteres jSON e, em seguida, como um objeto JavaScript;
- linha 54: a mensagem de erro de [fetch] encontra-se em [error.message];
- linhas 59-69: a função assíncrona [main] invoca a função assíncrona [initSession] de forma bloqueante (await na linha 62);
- linha 72: a função assíncrona [main] é iniciada e o código principal do script é então concluído. O script global será concluído quando as tarefas assíncronas iniciadas tiverem publicado os seus resultados no ciclo de eventos;
Os resultados da execução são os seguintes:
Caso 1: o servidor Laragon não está em execução
[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:
'tempo de espera de rede esgotado em: 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
Comentários
- linha 3: a solicitação HTTP falha após 2 segundos e 62 milissegundos devido ao tempo limite de 2 segundos que foi imposto à solicitação HTTP;
- linhas 4-9: o objeto JavaScript [error] foi interceptado pela cláusula [catch(error)]. Este objeto tem duas propriedades:
- [FetchError]: linha 4;
- [message]: linhas 10-12;
- linha 14: a mensagem de erro recebida pela função assíncrona [main];
Caso 2: o servidor Laragon é iniciado
[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',
'estado': 700,
'resposta': 'sessão iniciada com o tipo [json]' } objeto
[Done] exited with code=0 in 1.022 seconds
Comentários
- linha 3: [fetch] recebe a resposta do servidor após 375 ms;
- linhas 4-39: a estrutura do objeto JavaScript [response] que encapsula a resposta do servidor. Entre as suas propriedades, algumas podem ser do nosso interesse:
- [status] (linha 25): código HTTP da resposta do servidor;
- [statusText] (linha 26): texto associado a este código;
- [headers] (linha 27): os cabeçalhos HTTP da resposta do servidor;
- [body] (linha 8): representa o documento enviado pelo servidor. A instrução [fetch] fornece métodos para o utilizar;
- linhas 29-39: os cabeçalhos HTTP da resposta do servidor;
- linha 40: a função assíncrona [response.json()] publicou a sua resposta após 1 milésimo de segundo;
- linhas 42-44: o objeto JavaScript recebido pela função assíncrona [main];
Caso 3: o servidor Laragon está em execução, mas é-lhe enviado um comando incorreto:

- acima, na linha 26, é passado um tipo de sessão incorreto ao servidor;
Os resultados da execução são os seguintes:
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',
'estado': 703,
'resposta': 'parâmetro type=[x] inválido' } objeto
[Done] exited with code=0 in 0.712 seconds
- a resposta do servidor é recebida na linha 2;
- linha 24: pode-se ver que o código HTTP da resposta do servidor é 400, um código de erro. No entanto, o [fetch] não lançou nenhuma exceção. Enquanto o [fetch] receber uma resposta do servidor, processa-a e não lança uma exceção;
- linhas 41-43: a resposta obtida pela função assíncrona [main];
12.4. script [fetch-02]
O script seguinte retoma o script [fetch-01], eliminando todos os detalhes desnecessários:
'use strict';
// importações
import fetch from 'node-fetch';
import qs from 'qs';
// URL base do servidor de cálculo de impostos
const baseUrl = 'http://localhost/php7/scripts-web/impostos/versão-14/main.php?';
// inicialização da sessão
async function initSession() {
// opções da consulta HHTP [get /main.php?action=init-session&type=json]
const options = {
method: "GET",
timeout: 2000
};
// execução da consulta HTTP [get /main.php?action=init-session&type=json]
const response = await fetch(baseUrl + qs.stringify({
action: 'init-session',
type: 'json'
}), options);
// resultado recebido em jSON
return await response.json();
}
// a função main executa a função assíncrona [initSession]
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);
}
}
// teste
main();
Os resultados de uma execução normal:
[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',
'estado': 700,
'resposta: 'sessão iniciada com o tipo [json]' }
[Done] exited with code=0 in 0.56 seconds
Resultados de uma execução com exceção (o servidor Laragon é interrompido):
[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]
Retomamos aqui o script [fetch-01], que reescrevemos utilizando a biblioteca [axios]. Recorde-se que o nosso interesse nesta biblioteca reside no facto de ser portável entre o ambiente [node.js] e os dos navegadores habituais. Isto permite:
- numa fase 1, testar os nossos scripts num ambiente [node.js];
- numa fase 2, portá-los para um navegador;
O script [axios-01] retoma a estrutura do script [fetch-01]:
'use strict';
import axios from 'axios';
// configuração padrão do axios
axios.defaults.timeout = 2000;
axios.defaults.baseURL = 'http://localhost/php7/scripts-web/impots/version-14';
// inicialização da sessão
async function initSession(axios) {
// opções da solicitação HHTP [get /main.php?action=init-session&type=json]
const options = {
method: "GET",
// parâmetros da URL
params: {
action: 'init-session',
type: 'json'
}
};
// execução da consulta HTTP [get /main.php?action=init-session&type=json]
try {
// pedido assíncrono
const response = await axios.request('main.php', options);
// a resposta é o conjunto da resposta HTTP do servidor (cabeçalhos HTTP + a própria resposta)
// esta resposta é apresentada para se ver a sua estrutura
console.log("réponse axios=", response);
// a resposta do servidor encontra-se em [response.data]
return response.data;
} catch (error) {
// estamos aqui porque o servidor enviou um código de erro [404 Not Found, 500 Internal Server Error, ...]
// o parâmetro [error] é uma instância de exceção — pode assumir várias formas
// é apresentado para se ver a sua estrutura
console.log("axios error=", typeof (error), error);
if (error.response) {
// o servidor sinalizou um erro no estado HTTP, mas também enviou uma resposta
// por isso, esta encontra-se em [error.response.data]
// sabe-se que o servidor envia respostas jSON com a estrutura {ação, estado, resposta}
// e que, em caso de erro, a mensagem de erro está em [réponse]
return error.response.data;
} else {
// é gerado o erro
throw error;
}
}
}
// a função main executa a função assíncrona [initSession]
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);
}
}
// teste
main();
Comentários
- linha 2: importa-se a biblioteca [axios];
- linhas 5-6: configuração por predefinição das consultas HTTP. As opções [axios.defaults] são válidas para todas as consultas HTTP emitidas pelo objeto [axios], sem necessidade de as repetir em cada nova consulta;
- linha 5: tempo limite de 2 segundos para todas as solicitações;
- linha 6: todas as URL serão expressas em relação à URL de base;
- linha 9: a função assíncrona [initSession];
- linhas 11-18: as opções da solicitação HTTP que será emitida (para além das opções predefinidas já definidas nas linhas 5-6);
- linhas 14-17: os parâmetros da função URL [action=init-session&type=json]. O objeto [params] será automaticamente convertido numa cadeia de caracteres codificada URL;
- linha 22: chamada bloqueante da função assíncrona [axios.request]. O primeiro parâmetro é o URL de destino, construído a partir do [main.php] adicionado ao URL de base definido na linha 6. O segundo parâmetro é o objeto [options] das linhas 11 a 18;
- linha 25: [response] é um objeto JavaScript que encapsula a totalidade da resposta HTTP do servidor (cabeçalhos HTTP + documento de resposta). É apresentado para ver a sua estrutura JavaScript;
- linha 27: se o servidor enviou um documento, este encontra-se em [response.data]. Aqui sabemos que o servidor envia uma resposta jSON acompanhada do cabeçalho HTTP [Content-type : application/json]. A presença deste cabeçalho faz com que [axios] deserialize automaticamente [response.data] num objeto JavaScript;
- linha 28: a função [axios] pode lançar uma exceção. É aqui que a [axios] difere da [fetch]. É lançada uma exceção nos seguintes casos:
- a solicitação HTTP não pôde ser enviada (erro do lado do cliente);
- O servidor enviou um código de erro HTTP (400, 404, 500, …) (este aspeto é, na verdade, configurável). Recorde-se que, se este código de erro HTTP for acompanhado de uma resposta, o código [fetch] não lançava uma exceção, ao passo que o código [axios] lança uma. No entanto, se o código de erro HTTP for acompanhado por um documento, este é colocado em [error.response];
- linha 32: é apresentada a estrutura JavaScript do objeto [error];
- linhas 33-38: se o objeto [error] contiver um objeto [response], então é essa resposta que é devolvida ao código chamador;
- linhas 39-42: nos restantes casos, devolve-se o objeto [error] ao código chamador;
- linhas 47-57: a função assíncrona [main];
- linha 50: chamada bloqueante à função assíncrona [initSession]. Recupera-se a resposta jSON do servidor como um objeto JavaScript;
- linhas 53-56: interceção de um eventual erro. A mensagem de erro encontra-se em [error.message];
Os resultados da execução são os seguintes:
Caso 1: o servidor Laragon não está a funcionar
[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/impostos/versão-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
Comentários
- linhas 33-136: o objeto [error] contém muitas informações;
- [Error], linhas 3-9: uma descrição do erro que ocorreu;
- [config], linhas 10-27: a configuração da consulta HTTP que conduziu a este erro;
- [config.url], linhas 11-12: o destino URL;
- [config.method], linha 13: método da consulta;
- [config.params], linha 14: os parâmetros de URL;
- [config.headers], linhas 16-17: os cabeçalhos HTTP da consulta;
- [config.baseURL], linha 18: o URL de base do URL de destino;
- [config.timeout], linha 21: o tempo limite da solicitação;
- [code], linha 28: um código de erro;
- [request], linhas 29-133: uma descrição detalhada da solicitação HTTP. Note-se que a maioria das propriedades é precedida pelo sublinhado _, indicando que se trata de propriedades internas do objeto [request], não destinadas a serem utilizadas diretamente pelo programador;
- [response], linha 134: a resposta do servidor, neste caso inexistente;
- linha 138: a mensagem de erro apresentada pela função [main];
Caso 2: o servidor Laragon está em execução
[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',
'estado': 700,
'resposta': 'sessão iniciada com o tipo [json]' } }
succès ---------------------------------------------
réponse= { action: 'init-session',
'estado': 700,
'resposta': 'sessão iniciada com o tipo [json]' } objeto
[Done] exited with code=0 in 1.115 seconds
Comentários
- linhas 3-203: o objeto JavaScript [response] que encapsula a resposta HTTP do servidor;
- linha 3, [status]: o código HTTP da resposta;
- linha 4, [statusText]: o texto associado ao código HTTP anterior;
- linhas 5-13, [headers]: os cabeçalhos HTTP da resposta:
- linha 10, [Set-Cookie]: o cookie de sessão;
- linha 13, [Content-Type]: o tipo do documento enviado pelo servidor;
- linhas 14-31, [config]: a configuração do pedido HTTP enviado;
- linhas 32-199, [request]: o objeto JavaScript que detalha a solicitação HTTP enviada;
- linhas 200-203, [request.data]: o objeto JavaScript que encapsula a resposta jSON do servidor;
- linhas 205-207: a resposta recuperada pela função assíncrona [main];
Caso 3: é enviada uma solicitação [init-session] incorreta ao servidor Laragon;

Os resultados da execução são os seguintes:
[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',
'«estado»: 703,
'resposta': 'parâmetro type=[x] inválido' } },
isAxiosError: true,
toJSON: [Function] }
succès ---------------------------------------------
réponse= { action: 'init-session',
'estado': 703,
'resposta': 'parâmetro type=[x] inválido' } objeto
[Done] exited with code=0 in 0.69 seconds
Como o servidor respondeu com um código HTTP 400 (linha 15), o [axios] lançou uma exceção (mais uma vez, este comportamento é configurável). Embora o [axios] tenha lançado uma exceção, obtém-se, de facto, a resposta HTTP do servidor em [error.response] (linha 14) e o documento jSON enviado por [error.response.data] (linha 34). Linhas 41-43: a função [main] recupera corretamente a resposta jSON do servidor.
12.6. script [axios-02]
Agora que detalhámos os objetos manipulados pela biblioteca [axios] durante uma consulta HTTP, podemos reescrever o script [axios-01] da seguinte forma:
'use strict';
import axios from 'axios';
// configuração padrão do axios
axios.defaults.timeout = 2000;
axios.defaults.baseURL = 'http://localhost/php7/scripts-web/impots/versão-14';
// inicialização da sessão
async function initSession(axios) {
// opções da solicitação HHTP [get /main.php?action=init-session&type=json]
const options = {
method: "GET",
// parâmetros da URL
params: {
action: 'init-session',
type: 'json'
}
};
try {
// execução da consulta HTTP [get /main.php?action=init-session&type=json]
const response = await axios.request('main.php', options);
// a resposta do servidor está em [response.data]
return response.data;
} catch (error) {
// resposta do servidor
if (error.response) {
// a resposta jSON encontra-se em [error.response.data]
return error.response.data;
} else {
// o erro é reenviado
throw error;
}
}
}
// a função main executa a função assíncrona [initSession]
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);
}
}
// teste
main();
12.7. script [axios-03]
O script [axios-03] segue a metodologia do script [axios-02]. Desta vez, adiciona-se a solicitação HTTP [authentifier-utilisateur] ao servidor, o que é feito através de um POST:
'use strict';
import axios from 'axios';
import qs from 'qs'
// configuração do axios
axios.defaults.timeout = 2000;
axios.defaults.baseURL = 'http://localhost/php7/scripts-web/impots/versão-14';
// inicialização da sessão
async function initSession(axios) {
// opções da solicitação HHTP [get /main.php?action=init-session&type=json]
const options = {
method: "GET",
// parâmetros da URL
params: {
action: 'init-session',
type: 'json'
}
};
try {
// execução da consulta HTTP [get /main.php?action=init-session&type=json]
const response = await axios.request('main.php', options);
// a resposta do servidor está em [response.data]
return response.data;
} catch (error) {
// resposta do servidor
if (error.response) {
// a resposta jSON encontra-se em [error.response.data]
return error.response.data;
} else {
// o erro é reenviado
throw error;
}
}
}
async function authentifierUtilisateur(axios, user, password) {
// opções da solicitação HHTP [POST /main.php?action=authentifier-utilisateur]
const options = {
method: "POST",
headers: {
'«Content-type»: «application/x-www-form-urlencoded»,
},
// corpo do POST
data: qs.stringify({
user: user,
password: password
}),
// parâmetros do URL
params: {
action: 'authentifier-utilisateur'
}
};
try {
// execução da consulta HTTP [post /main.php?action=authentifier-utilisateur]
const response = await axios.request('main.php', options);
// a resposta do servidor está em [response.data]
return response.data;
} catch (error) {
// resposta do servidor
if (error.response) {
// a resposta jSON encontra-se em [error.response.data]
return error.response.data;
} else {
// o erro é reenviado
throw error;
}
}
}
// a função main executa as funções assíncronas uma a uma
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);
// autenticar-utilizador
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);
}
}
// teste
main();
Comentários
- linhas 38-70: a função assíncrona [authentifierUtilisateur];
- linha 39: é necessário efetuar a consulta [POST /main.php?action=authentifier-utilisateur];
- linhas 40-54: as opções da consulta HTTP;
- linha 41: trata-se de um POST;
- linhas 42-44: os parâmetros do POST serão codificados como URL num documento que o cliente envia juntamente com a sua consulta;
- linhas 46-49: a propriedade [data] deve conter a cadeia de caracteres POST URL codificada. Para tal, utiliza-se aqui a biblioteca [qs] importada na linha 3;
- linhas 55-69: para a execução da consulta, encontramos o mesmo código que no método [initSession];
- linhas 73-89: o método [asynchrone] chama sucessivamente, de forma bloqueante, os métodos [initSession, authentifierUtilisateur], nas linhas 77 e 82;
- linha 82: utiliza-se o par (admin, admin) como credenciais de ligação. Sabe-se que estas são reconhecidas pelo servidor;
Os resultados da execução são os seguintes:
[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',
'estado': 700,
'resposta': 'sessão iniciada com o tipo [json]' }
action authentifier-utilisateur en cours ---------------------------------------------
succès ---------------------------------------------
réponse= { action: 'authentifier-utilisateur',
'estado': 103,
'resposta':
[ 'pas de session en cours. Commencer par action [init-session]' ] }
[Done] exited with code=0 in 0.834 seconds
- linhas 9-12: a autenticação do utilizador falha: o servidor não registou o facto de termos iniciado uma sessão jSON. Isto deve-se ao facto de não termos reenviado o cookie de sessão enviado em resposta à primeira solicitação [init-session];
12.8. script [axios-04]
O script [axios-04] introduz duas melhorias no script [axios-03]:
- gerencia o cookie de sessão;
- fatoriza numa função [getRemoteData] o que é comum às funções [initSession] e [authentifierUtilisateur];
'use strict';
import axios from 'axios';
import qs from 'qs'
// configuração do Axios
axios.defaults.timeout = 2000;
axios.defaults.baseURL = 'http://localhost/php7/scripts-web/impots/versão-14';
// cookie de sessão
const sessionCookieName = "PHPSESSID";
let sessionCookie = '';
// inicialização da sessão
async function initSession(axios) {
// opções da solicitação HHTP [get /main.php?action=init-session&type=json]
const options = {
method: "GET",
// parâmetros da URL
params: {
action: 'init-session',
type: 'json'
}
};
// execução da consulta HTTP
return await getRemoteData(axios, options);
}
async function authentifierUtilisateur(axios, user, password) {
// opções da consulta HHTP [post /main.php?action=authentifier-utilisateur]
const options = {
method: "POST",
headers: {
'«Content-type»: «application/x-www-form-urlencoded»,
},
// corpo do POST
data: qs.stringify({
user: user,
password: password
}),
// parâmetros do URL
params: {
action: 'authentifier-utilisateur'
}
};
// execução do pedido HTTP
return await getRemoteData(axios, options);
}
async function getRemoteData(axios, options) {
// para o cookie de sessão
if (!options.headers) {
options.headers = {};
}
options.headers.Cookie = sessionCookie;
// execução da solicitação HTTP
let response;
try {
// solicitação assíncrona
response = await axios.request('main.php', options);
} catch (error) {
// o parâmetro [error] é uma instância de exceção — pode assumir várias formas
if (error.response) {
// a resposta do servidor está em [error.response]
response = error.response;
} else {
// o erro é reenviado
throw error;
}
}
// a resposta é o conjunto completo da resposta HTTP do servidor (cabeçalhos HTTP + a própria resposta)
// recupera-se o cookie de sessão, caso exista
const setCookie = response.headers['set-cookie'];
if (setCookie) {
// setCookie é um array
// procura-se o cookie de sessão neste array
let trouvé = false;
let i = 0;
while (!trouvé && i < setCookie.length) {
// procura-se o cookie de sessão
const results = RegExp('^(' + sessionCookieName + '.+?);').exec(setCookie[i]);
if (results) {
// guarda-se o cookie de sessão
// eslint-disable-next-line require-atomic-updates
sessionCookie = results[1];
// encontrado
trouvé = true;
} else {
// elemento seguinte
i++;
}
}
}
// a resposta do servidor está em [response.data]
return response.data;
}
// a função main executa as funções assíncronas uma a uma
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);
// autenticar-utilizador
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);
}
}
// teste
main();
Comentários
- linhas 14-26: a função [initSession]. Agora, limita-se a preparar a consulta HTTP para enviar ao servidor, mas não a executa. Confia essa função ao método [getRemoteDate] das linhas 49-95;
- linhas 28-47: a função [authentifierUtilisateur] segue o mesmo procedimento;
- linha 49: a função [getRemoteData] recebe as duas informações que lhe permitem executar uma solicitação HTTP:
- [axios], o objeto responsável por enviar a consulta e receber a resposta;
- [options], as opções de configuração da consulta a enviar ao servidor;
- linha 59: execução da consulta e espera bloqueante pela sua resposta jSON;
- linhas 60-68: gestão de uma eventual exceção;
- linha 64: recupera-se a resposta, que pode estar encapsulada no objeto de erro;
- linha 67: se o servidor tiver lançado uma exceção sem incluir a resposta do servidor, então o erro recebido é transmitido ao código chamador;
- a função [getRemoteData] gere o cookie de sessão:
- armazena-o na variável [sessionCookie] (linha 11) quando o recebe pela primeira vez;
- em seguida, reenvia-o em cada nova solicitação HTTP;
- linhas 72-92: o [getRemoteData] analisa cada resposta do servidor para verificar se este enviou o cabeçalho HTTP [Set-Cookie]. Sabe-se que o servidor envia um cookie de sessão denominado [PHPSESSID] (linha 10). É, portanto, este cookie que se procura (linha 10);
- linha 72: recuperam-se os cabeçalhos HTTP e [Set-Cookie], caso existam (não importa se são maiúsculas ou minúsculas). De facto, podem existir vários cabeçalhos [Set-Cookie], pelo que o que se recupera é uma matriz;
- linha 73: se tiver sido recuperada uma matriz de cookies;
- linhas 78-90: procura-se o cookie de sessão entre todos os cookies da tabela;
- linha 80: a expressão relacional que permite procurar o cookie de sessão no cookie n.º i;
- linha 81: se a comparação tiver produzido resultados;
- linha 84: temos em results[1] o primeiro parêntese do modelo da expressão relacional, ou seja, (PHPSESSID=xxxx) até ao ponto (não incluído) que termina o cookie de sessão;
- linhas 50-54: em cada pedido, o cookie de sessão é incluído nos cabeçalhos HTTP do pedido. Na primeira vez, este cookie está vazio e será, portanto, ignorado pelo servidor;
Os resultados da execução são os seguintes:
[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',
'estado': 700,
'resposta': 'sessão iniciada com o tipo [json]' }
action authentifier-utilisateur en cours ---------------------------------------------
succès ---------------------------------------------
réponse= { action: 'authentifier-utilisateur',
'estado': 200,
'resposta': 'Autenticação bem-sucedida [admin, admin]' }
[Done] exited with code=0 in 0.982 seconds