Destilando o XMLHttpRequest

{ October 3rd, 2007 }


cmilfont

Autor: cmilfont

O modelo que passou a ser conhecido como Ajax, termo criado por Jesse James Garrett, ficou famoso após o lançamento do GMail, a capacidade de obter recursos remotos sem precisar dar um refresh na página, modificou toda a forma de pensar no desenvolvimento web. A interface de usuário saía de uma estrutura puramente estática e passou a ser semelhante ao ambiente desktop.

Sua implementação é possível por causa do objeto javascript XMLHttpRequest que faz uma conexão assíncrona ao servidor e permite que o usuário continue seu trabalho sem bloquear a página. Na época não era especificado ainda pelo W3C.

O XMLHttpRequest surgiu como uma implementação proprietária da Microsoft e posteriormente criado no Mozilla em 2002, logo seguido pelos demais Browsers. A interface definida pelo W3C será o objeto de estudo desse artigo.

Uma conexão remota de forma assíncrona segue o seguinte esquema:

request_ajax.gif

  1. Um evento é disparado para dar início a execução;
  2. Um objeto XMLHttpRequest é criado e configurado;
  3. Uma requisição de um recurso é feita para o servidor;
  4. O servidor realizada sua lógica de negócio e devolve o recurso na forma de texto comum (que deve ser um xml em formado);
  5. Uma função de callback, previamente informada, manipula os dados retornados;
  6. A renderização ao usuário é realizada.

A criação e configuração do objeto, como o envio de requisição pelo XMLHttpRequest para a captura de um recurso remoto segue os seguintes passos:

//instancia um novo objeto
var ajax = new XMLHttpRequest();
//Configura uma function para a manipulação
//da reposta
ajax.onreadystatechange = handler;
//abre a conexão
ajax.open("GET", "test.xml");
//envia a requisição
ajax.send();

Caso a conexão seja pelo método "POST", o método send recebe como parâmetro, as variáveis a serem enviadas.

Criação do objeto

A Microsoft só implementou a interface XMLHttpRequest como um objeto nativo a partir do Internet Explorer 7, antes disso o objeto era um ActiveX. Apesar que os métodos e propriedades haviam sido copiados desse ActiveX, garantindo o funcionamento idêntico a todos os Browsers que suportam o XMLHttpRequest.

Então para as versões anteriores do IE, há a necessidade de criação customizada, eis:

    var http;
    try {
	    //cria o objeto caso o Browser
        //seja compatível com o W3C
        http = new XMLHttpRequest();
    } catch(e) {
        //caso IE < IE7
        //array com versões conhecidas
        //de implementações do ActiveX
        var msxml = [
                   'MSXML2.XMLHTTP.3.0', 
                   'MSXML2.XMLHTTP', 
                   'Microsoft.XMLHTTP'];
        for ( var i=0, len = msxml.length; i < len; ++i ) {
            try {
                //varre o array até identificar qual ActiveX
                http = new ActiveXObject(msxml[i]); break;
            } catch(e) {}
        }
    }

Conhecendo a Interface

Representação da Interface

interface XMLHttpRequest {
  // event handler
  attribute EventListener onreadystatechange;
  // state
  const unsigned short UNSENT = 0;
  const unsigned short OPEN = 1;
  const unsigned short SENT = 2;
  const unsigned short LOADING = 3;
  const unsigned short DONE = 4;
  readonly attribute unsigned short readyState;
  // request
  void open(in DOMString method, in DOMString url);
  void open(in DOMString method, in DOMString url, 
            in boolean async);
  void open(in DOMString method, in DOMString url, 
            in boolean async, in DOMString user);
  void open(in DOMString method, in DOMString url, 
            in boolean async, in DOMString user, 
            in DOMString password);
  void setRequestHeader(in DOMString header, in DOMString value);
  void send();
  void send(in DOMString data);
  void send(in Document data);
  void abort();
  // response
  DOMString getAllResponseHeaders();
  DOMString getResponseHeader(in DOMString header);
  readonly attribute DOMString responseText;
  readonly attribute Document responseXML;
  readonly attribute unsigned short status;
  readonly attribute DOMString statusText;
};

Event Listener

A Interface XMLHttpRequest possui um EventListener denominado "onreadystatechange", que é um manipulador de eventos que é invocado quando o evento readystatechange é acionado. Passamos uma função de tratamento a esse EventListener que verificará os estados da conexão.

//obtem uma instancia
var ajax = new XMLHttpRequest();
//seta o EventListener com o handler
ajax.onreadystatechange = function() {
    //testa se já recebeu e foi com sucesso
    if(this.readyState == 4  && this.status == 200) {
        //obtem o xml enviado pelo servidor
        var xml = this.responseXML;
    }
};

Propriedades

A Interface possui uma propriedade denominada "readyState" que recebe o valor de uma constante que representa o estado atual da conexão. As constantes que representam os estados são definidos como:

  1. UNSENT = 0; //Apenas instanciado
  2. OPEN = 1; //aberta
  3. SENT = 2; //enviada
  4. LOADING = 3; //abrindo
  5. DONE = 4; //realizada

A propriedade "status" da Interface, representa o código de status do protocolo HTTP enviado pelo servidor, como o código "200" para uma requisição com sucesso. Caso o recurso não esteja disponível, é lançado uma exceção INVALID_STATE_ERR pelo Browser. A lista de "HTTP Status Code" você encontra aqui.

A propriedade "statusText", é a mensagem texto do "HTTP status code", e é recebida logo após ele, como "Not Found" para o "status code" 404, que indica que o recurso não foi encontrado no servidor de destino.

As propriedades "responseText" e "responseXML", devolvem a resposta do servidor na forma de uma DOMString (texto) e Document (da especificação DOM) respectivamente, em outras palavras, devolve um texto puro no caso do responseText ou um xml parseado no caso do responseXML.

Métodos

O método "abort" cancela a requisição, entretanto ele percorre uma série de atividades dependendo do estado da requisição no momento que é invocado. Para uma explanação mais apropriada no mecanismo que o abort realizada, visite esse link da especificação da Interface.

O método "open" é overloaded na Interface, apesar de não existir overloading em javascript. Leve em consideração que é um só, na implementação o número de argumentos passados tem a ver com a funcionalidade dependente do método, exemplo, os parâmetros "user" e "password" são necessários apenas no caso de url restrita no servidor, e caso o parâmetro "async" não seja definido, a conexão é assíncrona por default. Os primeiro parâmetro representa o método HTTP de requisição, que pode ser dos tipos: POST, GET, PUT, HEAD, DELETE e OPTIONS. O segundo parâmetro é a url que receberá a requisição, o terceiro, quarto e quinto são opcionais como já falado.

O método "setRequestHeader" é usado antes do método "send" e habilita enviar informações de cabeçalho na requisição quando for disparado os recursos ao servidor.

O método "send" envia a requisição com o argumento opcional "data" que é do tipo "Text" ou "Document".

Quando o método de requisição escolhido é o GET, os argumentos a serem enviados ao servidor é usado no parâmetro "url", como "/pagina.jsp?id=1&nome=milfont". Já no método POST, os dados serão enviados como argumento do método "send"

Código completo de uma submissão Ajax

    var http;
    try {
        http = new XMLHttpRequest();
    } catch(e) {
        var msxml = [
                   'MSXML2.XMLHTTP.3.0', 
                   'MSXML2.XMLHTTP', 
                   'Microsoft.XMLHTTP'];
        for ( var i=0, len = msxml.length; i < len; ++i ) {
            try {
                http = new ActiveXObject(msxml[i]); break;
            } catch(e) {}
        }
    }
    http.onreadystatechange = function() {
        if(this.readyState == 4  && this.status == 200) {
           var xml = this.responseXML;
        }
    };
    var params = "id=1&name=milfont";
    http.open("POST", "pagina.jsp");
    http.setRequestHeader("Content-type", 
	                  "application/x-www-form-urlencoded");
    http.setRequestHeader("Content-length", params.length);
    http.setRequestHeader("Connection", "close");
    http.send(params);

Para mais features nas próximas versões da especificação mas que já podem existir nas implementações, visite esse link.

Categories: Ajax, JavaScript, XMLHttpRequest ~ ~ Trackback


Assine os comentários deste artigo.


11 Responses to “Destilando o XMLHttpRequest”

  1. 1
    Rafael Carneiro

    Quem quer aprender a utilizar AJAX, essa é a solução. Exemplo bastante didático e prático, mostrando todas as características necessárias para construir códigos utilizando AJAX.

    Excelente post. :)

  2. 2
    Frameworks Ajax - CMilfont Tech

    […] da utilização de chamadas ao servidor, como somente os browsers modernos implementam o objeto XHR, as estratégias de IFrame e Scripttag são delegadas como estratégias secundárias, alguns […]

  3. 3
    Anibal Mantovani Diniz, MSc » Uma introdução ao conceito de Ajax

    […] Destilando o XMLHttpRequest – uma introdução interessante para quem quer saber o que é AJAX. Veja mais em: AJAX […]

  4. 4
    Rodrigo Galba

    ótimo post!

    agora só uma duvida:
    estou enviando uma mensagem como: ‘este eh meu email’
    sendo q o formulario esta concatenando as palavras: ‘esteehmeuemail’
    o que pode ser?

    valew…

  5. 5
    JSONRequest para evitar o “Eval” - CMilfont Tech

    […] um novo objeto como serviço nativo nos navegadores, JSONRequest, devido a ineficiência do objeto XMLHttpRequest para as novas aplicações nas próximas geração WEB (WEB 2+). Um dos pontos principais desse […]

  6. 6
    Rodrigo Galba

    olá.
    eu estava usando o XmlHttpRequest e ele estava ‘concatenando’ os dados do post, como eu tinha dito num comentario anterior.
    eu resolvi isso com a função encodeUri() do javascript.
    seu post me ajudou como usar o XmlHttpRequest num envio via method=post.

    otimo post! continue assim.
    vlew

  7. 7
    Resumo javascript - Jan 2008 - CMilfont Tech

    […] http://www.milfont.org/tech/2007/10/03/destilando-o-xmlhttprequest/ […]

  8. 8
    Lorran Luiz

    Ótimo artigo!

  9. 9
    Ajax Crossbrowser no IE8 e FF3 - CMilfont Tech

    […] confusão muito comum até em desenvolvedores profissionais é não saber que o objeto XHR segue o mesmo princípio de segurança do javascript e por isso não pode executar uma chamada […]

  10. 10
    Aron

    And there is what some alternative? 😉

  11. 11
    Andre Bueno

    Ótimo post! Muito esclarecedor… Vai ajudar um bocado em diversas implementações.

Leave a Reply