Sursa tutorial: cursul de Programare Web – Universitatea Politehnica Bucuresti, pentru informatii la zi sunteti rugati sa vizitati acest site.
Bine v-am gasit pe ItAssistant.org! In tutorialul de astazi va vom prezenta arhitectura AJAX si integrarea ei cu jQuery.
AJAX
Termenul AJAX descrie o arhitectura pentru aplicatii web bazata pe HTTP scripting si obiectul XMLHttpRequest. Termenul a fost creat de Jesse James Garret in eseul sau din februarie 2005.
Punctul cheie al acestei abordari este faptul ca paginile web nu trebuie reincarcate complet iar datele interschimbate au de obicei un volum mic. Efectul este o comportare a aplicatiilor web mult imbunatatita din puctul de vedere al experientei utilizatorului.
AJAX poate fi formalizat intr-un mecanism RPC (spre exemplu), insa in cele mai multe cazuri se prefera solutii mai simple si mai rapide. De multe ori, XML nici macar nu mai este folosit, preferandu-se formate mai lightweight (JSON sau chiar plain-text).
Implementare AJAX
XMLHTTPRequest
Obiectul XMLHTTPRequest a fost introdus pentru a se putea controla protocolul HTTP din Javascript sincron si asincron, fara a se apela la artificii de genul <iframe>-urilor. Din pacate, obiectul nu a fost niciodata standardizat si de aceea intalnim diferite implementari in diferite browsere (IE, of course).
// normal browser (IE 7 included) var request = new XMLHttpRequest(); // IE 5 or 6 var request = new ActiveXObject("Msxml2.XMLHTTP"); // or, depending on installed client libraries var request = new ActiveXObject("Microsoft.XMLHTTP");
De obicei, se creaza metode care abstractizeaza aceste diferente de instantiere. Un exemplu este prezentat mai jos:
var HTTP = { // This is a list of XMLHttpRequest-creation factory functions to try _factories: [ function() { return new XMLHttpRequest(); }, function() { return new ActiveXObject("Msxml2.XMLHTTP"); }, function() { return new ActiveXObject("Microsoft.XMLHTTP"); } ], // When we find a factory that works, store it here. _factory: null, // Create and return a new XMLHttpRequest object. // // The first time we're called, try the list of factory functions until // we find one that returns a non-null value and does not throw an // exception. Once we find a working factory, remember it for later use. // newRequest: function() { if (HTTP._factory != null) return HTTP._factory(); for(var i = 0; i < HTTP._factories.length; i++) { try { var factory = HTTP._factories[i]; var request = factory(); if (request != null) { HTTP._factory = factory; return request; } } catch(e) { continue; } } // If we get here, none of the factory candidates succeeded, // so throw an exception now and for all future calls. HTTP._factory = function() { throw new Error("XMLHttpRequest not supported"); } HTTP._factory (); } };
Observatii:
- exemplul de mai sus aplica o varianta a design pattern-ului Singleton pentru a obtine o cerere XMLHttp;
- observati membrul _factory al clasei HTTP: acesta este initial null, insa va retine un obiect de tip XMLHttpRequest;
- observati functia newRequest:
- daca _factory a fost creat, functia il intoarce;
- altfel, se incearca succesiv apelurile retinute in vectorul _factories; in functie de browser, unul din aceste apeluri va avea succes (altfel, se va arunca exceptie); rezultatul apelului care a avut succes este retinut in _factory, si intors de functie
Trimiterea unei cereri cu XMLHttpRequest
Dupa ce crearea unui astfel de obiect, urmatoarele metode sunt puse la dispozitie pentru construirea unei cereri catre server:
- request.open(method, url, asynchronous, [username, password])
- request.setRequestHeader(name, value)
- request.send(content)
Raspunsul este stocat in cadrul aceluiasi obiect. Inspectand urmatoarele metode si proprietati se poate verifica si manipula raspunsul:
- request.status: intoarce codul HTTP asociat raspunsului (poate fi 200 pentru succes, 404 daca pagina nu exista, etc)
- request.statusText: intoarce un text asociat codului HTTP din raspuns;
- request.responseText: intoarce raspunsul efectiv al cererii HTTP;
- request.getResponseHeader(): intoarce header-ul raspunsului;
Cereri sincrone
O cerere sincrona se efectueaza atunci cand cel de-al treilea parametru al metodei open este false. Acest lucru determina blocarea executiei de cod Javascript pana in momentul primirii raspunsului de la server.
Secventa de cod de mai jos exemplifica o cerere sincrona:
var request = HTTP.newRequest(); request.open("GET", url, false); //prepare a HTTP request using GET method, to 'url'; request type is synchronous; request.setRequestHeader("User-Agent", "XMLHttpRequest"); //set header fields request.setRequestHeader("Accept-Language", "en"); request.setRequestHeader("If-Modified-Since", lastRequestTime.toString()); request.send(null);//send an empty request; the request is blocking; //after send method returns, check response if (request.status == 200) { // We got the server's response. Display the response text. alert(request.responseText); } else { // Something went wrong. Display error code and error message. alert("Error " + request.status + ": " + request.statusText); } // or, for XML responses if (request.status == 200) { // Make sure there were no errors // Make sure the response is an XML document if (request.getResponseHeader("Content-Type") == "text/xml") { var doc = request.responseXML; // Now do something with the response document } }
Observatii:
- din cauza ca cererea este sincrona, apelul send din exemplul de mai sus este blocant; functia va intoarce doar dupa primirea raspunsului de la server;
- apoi, se poate inspecta codul HTTP (folosind membrul status), continutul si/sau header-ul raspunsului;
Cereri asincrone
In momentul in care raspunsul unei cereri HTTP realizata folosind XMLHttpRequest intarzie, sau ajunge mai greu (din diverse motive), pagina se blocheaza (din cauza apelului blocant al send). Acest lucru poate fi neplacut!
Tocmai de aceea, din punct de vedere al experientei utilizatorului, este mult mai bine ca aceste cereri sa fie non-blocante (asincrone). In aceasta situatie, se pune problema depistarii momentului in care cererea este primita (si executarea unei actiuni corespunzatoare, pe baza raspunsului).
Pentru aceasta avem la dispozitie urmatoarele:
- readystate: este o proprietate a obiectului XMLHttpRequest, si contine starea cererii curente:
- 0: open() inca nu a fost apelat
- 1: open() a fost apelat, dar send() inca nu a fost apelat
- 2: send() a fost apelat, dar serverul nu a raspuns inca
- 3: se primesc date de la server (atentie, implementarile difera intre browsere aici)
- 4: toate datele au fost primite de la server
- onreadystatechange: este un eveniment; i se atribuie o functie, care este apelata de cate ori starea cererii se modifica;
Secventa de cod de mai jos prezinta o cerere asincrona (AJAX):
// Create an XMLHttpRequest using the utility defined earlier var request = HTTP.newRequest(); // Register an event handler to receive asynchronous notifications. // This code says what to do with the response, and it appears in a nested // function here before we have even submitted the request. request.onreadystatechange = function() { if (request.readyState == 4) { // If the request is finished if (request.status == 200) // If it was successful alert(request.responseText); // Display the server's response } } // Make a GET request for a given URL. We don't pass a third argument, // so this is an asynchronous request request.open("GET", url); // We could set additional request headers here if we needed to. // Now send the request. Since it is a GET request, we pass null for // the body. Since it is asynchronous, send() does not block but // returns immediately. request.send(null);
Same-origin policy
Aceasta politica de securitate restrictioneaza continutul cu care poate interactiona codul Javascript la orginea documentului din contextul caruia se executa scriptul. Originea documentului este definita ca o combinatie intre protocol, host si port (determinate prin URL).
Este important sa retineti ca orginea este legata de document si nu de script: puteti avea un script incarcat de pe alt domeniu din care sa efectueze cereri catre originea documentului vostru. Se pot face exceptii pentru cererile intre subdomenii daca se foloseste proprietatea domain a obiectului document. Aici gasiti o explicatie mai detaliata.
Aceasta implementare de securitate este necesara pentru a preveni, printre altele, furtul de informatie. Ganditi-va la posibilitatea ca un site care ruleaza cod malitios sa deschida si sa aiba acces la un alt tab in care aveti afisate informatii sensibile.
In cazul particular al folosirii obiectului XMLHttpRequest, s-ar referi la faptul ca se pot face cereri doar peste HTTP si doar catre locul din care originat documentul din care a pornit cererea.
Totusi, cererile AJAX cross-domain pot avea o utilitate foarte mare – nu ar mai fi nevoie sa se faca proxying server-side pentru a putea servi continut de pe alte domenii.
Solutia la care s-a ajuns este folosirea headerelor Origin: [domeniu emitent] de catre cel ce emite cererea si Access-Control-Allow-Origin: [* / lista acceptata de domenii, separate prin ,]. Daca headerul Access-Control-Allow-Origin contine domeniul emitent (sau *) atunci browserul primeste si interpreteaza raspunsul. Mai multe detalii puteti vedea aici.
AJAX in jQuery
jQuery ofera metode care faciliteaza efectuarea actiunilor AJAX. Metodele sunt bine documentate si demonstrate pe site-ul cu documentatia.
Este mult mai facila folosirea jQuery decat crearea de obiecte care sa abstractizeze XMLHttpRequest etc.
Trebuie insa avut in vedere faptul ca fara o intelegere buna a protocolului HTTP, a limbajului si a modului de functionare a browserelor este mult mai greu sa scrieti cod de calitate.
Exemplul de mai jos demonstreaza folosirea jQuery pentru a face cereri peste HTTP:
// on page load $(document).ready(function () { // reference a button var button = $(...); // add an event handler button.click(function () { // do an ajax request $.ajax({ // specify the url to request url: 'document.html', // request method type: 'GET', // dataType, can be used for automated parsing dataType: 'html', // timeout for this request timeout: 1000, // error callback error: function(){ alert('Error loading HTML document'); }, // successful request callback success: function(html){ // do something with html } }); }); });
Related posts:
- Tutorial JavaScript – Introducere
- Tutorial jQuery – Write Less, Do More
- Aspecte cheie ale dezvoltarii aplicatiilor WEB
- Securitatea aplicatiilor WEB – partea a II-a
- Securitatea aplicatiilor WEB – partea I



