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:
- Um evento é disparado para dar início a execução;
- Um objeto XMLHttpRequest é criado e configurado;
- Uma requisição de um recurso é feita para o servidor;
- 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);
- Uma função de callback, previamente informada, manipula os dados retornados;
- 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:
- UNSENT = 0; //Apenas instanciado
- OPEN = 1; //aberta
- SENT = 2; //enviada
- LOADING = 3; //abrindo
- 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.