MySQL Java JavaScript PHP Python HTML-CSS C-sharp C++ Go

Cereri AJAX și XMLHttpRequest

Obiectul XMLHttpRequest

Codul JavaScript poate interacționa cu o resursă de pe internet, de exemplu, cu un site web sau un serviciu web, adică cu un server. Pentru interacțiunea codului JavaScript cu serverul, se utilizează adesea o tehnologie precum Ajax. Ajax reprezintă tehnologia pentru trimiterea de cereri către server din codul client JavaScript fără a reîncărca pagina.

Termenul în sine este un acronim pentru Asynchronous JavaScript And XML. Astfel, inițial, AJAX presupunea o interacțiune asincronă între client și server prin intermediul datelor în format XML. Deși acum, formatul JSON a înlocuit în mare parte formatul XML.

Una dintre metodele de trimitere a cererilor ajax este utilizarea obiectului XMLHttpRequest. Acest obiect este creat folosind funcția-constructor cu același nume:

const xhr = new XMLHttpRequest();

Pentru configurarea și trimiterea cererilor ajax, obiectul XMLHttpRequest oferă o serie de metode:

  • abort(): întrerupe cererea
  • getAllResponseHeaders(): returnează toate anteturile răspunsului HTTP sub formă de șir
  • getResponseHeader(header): returnează valoarea antetului header
  • open(method, url[, async[, user[, password]]]): inițializează cererea ajax

Această funcție acceptă cinci parametri, dintre care primii doi sunt obligatorii:

  • method: tipul cererii ("GET", "POST", "PUT", "DELETE" etc.)
  • url: adresa resursei către care se trimite cererea
  • async: o valoare booleană care indică dacă cererea va fi asincronă. Dacă valoarea este true (valoarea implicită), atunci cererea este asincronă

Modul sincron și asincron diferă prin faptul că, în modul sincron, restul codului JavaScript nu poate fi executat până când cererea nu este finalizată. Dacă cererea este trimisă în mod asincron, atunci codul JavaScript poate fi executat în paralel cu cererea. Și, în majoritatea cazurilor, se utilizează modul asincron.

  • user: numele utilizatorului, utilizat pentru autentificarea acestuia pe server (adică pentru a determina care utilizator a făcut cererea), implicit este null
  • password: parola utilizatorului, utilizată pentru autentificarea acestuia pe server, implicit este null
  • overrideMimeType(mime): suprascrie tipul MIME returnat de server
  • send(data): trimite cererea. Folosind parametrul opțional data, se pot transmite date care vor fi trimise pe server. Dacă acestui parametru nu i se atribuie nicio valoare, atunci valoarea sa implicită este null
  • setRequestHeader(header, value): stabilește valoarea value pentru antetul header, care va fi trimis în cerere

Proprietăți ale XMLHttpRequest

În plus față de metode, obiectul XMLHttpRequest oferă o serie de proprietăți care permit configurarea trimiterea cererii sau extragerea datelor primite de la server:

  • response: returnează răspunsul serverului. Răspunsul poate reprezenta obiecte ArrayBuffer, Blob, Document, obiect JSON, un șir sau null (dacă cererea încă nu a fost finalizată sau a eșuat)
  • responseType: returnează tipul răspunsului. Există următoarele tipuri: ": un șir gol ; arraybuffer: răspunsul reprezintă un obiect ArrayBuffer, care conține date binare ; blob: răspunsul reprezintă un obiect Blob, care conține date binare ; document: răspunsul reprezintă un obiect Document (document HTML/XML) ; json: răspunsul reprezintă date în format json ; text: răspunsul reprezintă text
  • responseText: returnează răspunsul serverului sub formă de șir sau valoarea null (dacă cererea încă nu a fost finalizată sau a eșuat)
  • responseXML: returnează un obiect Document (document HTML/XML), dacă răspunsul de la server este în format XML/HTML
  • readyState: stochează stările cererii, care reprezintă un număr:

0: obiectul XMLHttpRequest a fost creat, dar metoda open() încă nu a fost apelată pentru inițializarea obiectului

1: metoda open() a fost apelată, dar cererea încă nu a fost trimisă prin metoda send()

2: cererea a fost trimisă, anteturile și starea răspunsului au fost primite și sunt gata de utilizare

3: răspunsul a fost primit de la server

4: executarea cererii a fost complet finalizată (chiar dacă s-a primit un cod de eroare, de exemplu, 404)

Prin verificarea acestei proprietăți, putem înțelege la ce etapă se află cererea.

  • status: conține codul de stare al răspunsului HTTP, care a venit de la server. Prin intermediul codului de stare, putem judeca succesul cererii sau erorile care ar putea să apară în timpul execuției acesteia. De exemplu, codul de stare 200 indică faptul că cererea a fost finalizată cu succes. Codul 403 indică necesitatea autorizării pentru executarea cererii, iar codul 404 informează că resursa nu a fost găsită etc.
  • statusText: returnează textul stării răspunsului, de exemplu, "200 OK"
  • timeout: stabilește timeout-ul - timpul în milisecunde în care cererea poate fi executată. Dacă acest timp expiră, iar cererea încă nu a fost finalizată, atunci cererea este întreruptă
  • withCredentials: determină dacă în cerere trebuie incluse credențialele, de exemplu, fișierele cookie

Evenimente și gestionari de evenimente XMLHttpRequest

Pentru a urmări starea cererii, se pot utiliza evenimentele XMLHttpRequest:

  • abort: se declanșează după întreruperea cererii. Pentru setarea gestionarului se utilizează proprietatea onabort
  • progress: se declanșează în timpul executării cererii. Pentru setarea gestionarului se utilizează proprietatea onprogress
  • load: se declanșează după finalizarea cererii. Pentru setarea gestionarului se utilizează proprietatea onload
  • loadend: se declanșează după finalizarea cu succes a cererii. Pentru setarea gestionarului se utilizează proprietatea onloadend
  • error: se declanșează în cazul apariției unei erori. Pentru setarea gestionarului se utilizează proprietatea onerror
  • loadstart: se declanșează după lansarea cererii. Pentru setarea gestionarului se utilizează proprietatea onloadstart
  • timeout: se declanșează dacă cererea este întreruptă din cauza timeout-ului. Pentru setarea gestionarului se utilizează proprietatea ontimeout
  • readystatechange: apare de fiecare dată când se modifică valoarea proprietățiireadyState. Pentru setarea gestionarului se utilizează proprietatea onreadystatechange

Pentru setarea gestionarilor de evenimente se poate utiliza una dintre următoarele proprietăți ale XMLHttpRequest:

  • onabort: este apelat când cererea a fost întreruptă prin metoda abort()
  • onerror: este apelat în cazul apariției unei erori
  • onload: este apelat când cererea a fost finalizată cu succes și răspunsul este disponibil
  • onloadend: este apelat după finalizarea cu succes a cererii
  • onloadstart: este apelat după lansarea cererii
  • onprogress: este apelat în timpul executării cererii
  • onreadystatechange: este apelat la modificarea stării cererii
  • ontimeout: este apelat dacă cererea este întreruptă din cauza timpului de așteptare
  • upload: poate fi utilizat pentru a urmări starea la încărcarea datelor

Procesul de executare a cererii ajax

În general, procesul de executare a unei cereri ajax cu ajutorul XMLHttpRequest arată astfel:

1. Se creează un obiect XMLHttpRequest

const request = new XMLHttpRequest();

2. Se stabilește gestionarul de evenimente de încărcare (de exemplu, prin proprietatea onload), care va fi apelat după finalizarea cererii HTTP

request.onload = (event) => { console.log("request finished");};

3. Se lansează cererea HTTP cu ajutorul metodei open(). Metodei i se transmit metoda HTTP care va fi utilizată pentru cerere (de exemplu, GET sau POST), adresa URL la care trebuie trimisă cererea și, dacă este necesar, alți parametri opționali

request.open("GET", "http://localhost/hello");

4.Dacă este necesar, se efectuează configurarea suplimentară a cererii HTTP. De exemplu, cu ajutorul metodei setRequestHeader() se pot defini anteturile care vor fi trimise împreună cu cererea. Totuși, este important să efectuați această configurare după pasul anterior, adică după apelarea metodei open(), dar înainte de pasul următor, adică înainte de apelarea metodei send()

request.setRequestHeader("Accept", "text/plain"); // setarea antetului pentru acceptarea datelor

5. Se trimite efectiv cererea HTTP prin apelarea metodei send(). La dorință, în această metodă se pot transmite date care vor fi trimise pe server

request.send()

Definirea resursei pe server

Deoarece Ajax presupune interacțiunea dintre client și server, pentru lucrul cu Ajax ne va fi necesară o anumită resursă de rețea la care ne vom adresa. Pentru emularea resursei de rețea, vom utiliza un server web local. Serverul web poate fi oricare. În acest caz, vom folosi cea mai simplă variantă - Node.js, deoarece această tehnologie este destul de simplă, disponibilă pentru toate sistemele de operare principale și, de asemenea, permite utilizarea JavaScript pentru crearea aplicațiilor.

Dar, desigur, înainte de a crea aplicația, este necesar să instalați Node.js. În acest caz, nu va fi necesară nicio cunoștință de Node.js, tot codul utilizat este descris în detaliu. Dar, din nou, în loc de Node.js, acesta ar putea fi orice altă tehnologie de server - PHP, ASP.NET, Python etc. sau un anumit server web, cum ar fi Apache sau IIS.

Așadar, vom crea pe discul dur o directorie pentru fișierele serverului web. De exemplu, în cazul meu, aceasta este directoria C:\app. Apoi, în această directorie, vom defini fișierul serverului. Să presupunem că se numește server.js și are următorul cod:

const http = require("http");
const fs = require("fs");
   
http.createServer(function(request, response){
     
   if(request.url == "/hello"){
       response.end("Hello FDC.COM");
   }
   else{
       fs.readFile("index.html", (error, data) => response.end(data));
   }
}).listen(3000, ()=>console.log("Serverul a fost lansat la adresa http://localhost:3000"));

Acesta este cel mai primitiv server, suficient pentru scopul nostru. Să trecem pe scurt prin cod. La început, se conectează pachetele cu funcționalitatea pe care intenționăm să o utilizăm:

const http = require("http");   // pentru prelucrarea cererilor primite
const fs = require("fs");       // pentru citirea fișierului index.html de pe discul dur

Pentru crearea serverului, se utilizează funcția http.createServer(). Acestei funcții i se transmite un gestionar-funcție, care este apelat de fiecare dată când serverul primește o cerere. Această funcție are doi parametri: request (conține datele cererii) și response (gestionează trimiterea răspunsului).

În gestionar-funcție, cu ajutorul proprietății request.url, putem afla la ce resursă pe server a fost adresată cererea. Astfel, în acest caz, dacă a venit o cerere pe calea "/hello" (condițional la resursa "/hello"), atunci trimitem ca răspuns cu ajutorul metodei response.end() textul "Hello FDC.COM":

if(request.url == "/hello"){
   response.end("Hello FDC.COM");
}

Dacă cererea a fost adresată la o altă resursă, atunci trimitem fișierul index.html, pe care îl vom defini mai târziu:

else{
   fs.readFile("index.html", (error, data) => response.end(data));
}

Pentru citirea fișierelor, se utilizează funcția integrată fs.readFile(). Primul parametru al funcției - adresa fișierului (în acest caz, se presupune că fișierul index.html se află în aceeași directorie cu fișierul serverului server.js). Al doilea parametru - o funcție care este apelată după citirea fișierului și primește conținutul său prin al doilea parametru data. Apoi, conținutul citit poate fi trimis de asemenea cu ajutorul funcției response.end(data).

La sfârșit, cu ajutorul funcției listen(), lansăm serverul web pe portul 3000. Adică, serverul va fi lansat la adresa http://localhost:3000/

Executarea cererii ajax

Acum, în directoria serverului, vom defini un fișier simplu index.html

Vom defini în acest fișier următorul conținut:

<!DOCTYPE html>
<html>
<head>
   <meta charset="utf-8" />
   <title>FDC.COM</title>
</head>
<body>
<script>
const xhr = new XMLHttpRequest();
// Cererea GET către resursa /hello
xhr.open("GET", "/hello");

// gestionar pentru primirea răspunsului de la server
xhr.onload = () => {
   if (xhr.status == 200) {                // dacă codul de răspuns este 200
       console.log(xhr.responseText);      // afișăm răspunsul primit în consola browserului
   } else {                                // altfel, afișăm textul stării
       console.log("Răspuns server: ", xhr.statusText);
   }
};
xhr.send();     // executăm cererea
</script>
</body>
</html>

Aici, în metoda xhr.open(), ca tip de cerere se transmite tipul "GET", iar ca adresă a resursei - "/hello".

xhr.open("GET", "/hello");

Pentru a urmări finalizarea cererii, stabilim un gestionar pentru evenimentul load cu ajutorul proprietății xhr.onload:

xhr.onload = () => {
   if (xhr.status == 200) {

               // dacă codul de răspuns este 200
       console.log(xhr.responseText);      // afișăm răspunsul primit în consola browserului
   } else {                                // altfel, afișăm textul stării
       console.log("Răspuns server: ", xhr.statusText);
   }
};

În acest caz, ca gestionar al evenimentului acționează o expresie lambda. Și când cererea se finalizează, acest gestionar este activat. Dacă cererea a fost procesată cu succes, atunci, implicit, serverul trimite codul de stare 200. Cum ne amintim din codul serverului, la adresarea pe calea "/hello", serverul trimite clientului un șir.

Și pentru a obține acest șir, ne adresăm proprietății xhr.responseText. Dacă însă în procesul de adresare la server a apărut o eroare sau codul de stare nu este 200, atunci cu ajutorul proprietății xhr.statusText se afișează textul stării răspunsului.

Și, în final, de fapt, executăm cererea:

xhr.send();     // executăm cererea

Astfel, la încărcarea acestei pagini web, va fi executată cererea ajax către server.

Acum, în consolă, vom trece la directoria serverului cu ajutorul comenzii cd și vom lansa serverul cu ajutorul comenzii node server.js

După lansarea serverului, putem trece în browser la adresa http://localhost:3000, unde ne va fi afișată pagina, în codul JavaScript al căreia va avea loc adresarea la resursa "/hello":

În urma adresării la resursa "/hello", serverul va trimite șirul "Hello FDC.COM", pe care îl vom putea obține pe pagina web.

În exemplul de mai sus a fost utilizată calea relativă, dar de asemenea am fi putut folosi o cale absolută cu indicarea protocolului, adresei serverului și portului:

xhr.open("GET", "http://localhost:3000/hello");

În locul evenimentului load, am fi putut de asemenea să procesăm evenimentul readystatechange al obiectului XMLHttpRequest, care apare de fiecare dată când se modifică valoarea proprietății readyState:

<!DOCTYPE html>
<html>
<head>
   <meta charset="utf-8" />
   <title>FDC.COM</title>
</head>
<body>
<script>
const xhr = new XMLHttpRequest();
// Cererea GET către resursa /hello
xhr.open("GET", "/hello");

// gestionar pentru primirea răspunsului de la server
xhr.onreadystatechange = () => {
   if (xhr.readyState == 4) {                  // dacă cererea este finalizată
       if (xhr.status == 200) {                // dacă codul de răspuns este 200
           console.log(xhr.responseText);      // afișăm răspunsul primit în consola browserului
       } else {                                // altfel, afișăm textul stării
           console.log("Răspuns server: ", xhr.statusText);
       }
   }
};
xhr.send();     // executăm cererea
</script>
</body>
</html>

Aici, în gestionarul evenimentului, se verifică mai întâi starea cererii - dacă codul stării este 4, atunci se procesează răspunsul de la server. Restul logicii este aceeași ca și în cazul anterior.