Essa palestra foi ministrada na SEAD-CE (hoje SEPLAG-CE), a primeira que falei sobre Ajax.
Posted in Ajax, Web Development, XMLHttpRequest, cursos, web2.0 ~ 1 Comment
Essa palestra foi ministrada na SEAD-CE (hoje SEPLAG-CE), a primeira que falei sobre Ajax.
Posted in Ajax, Web Development, XMLHttpRequest, cursos, web2.0 ~ 1 Comment
Para implementar o dinamismo nas nossas páginas, usando o Javascript, precisamos trocar informações entre as camadas físicas diferentes, o cliente (por intermédio de um Browser) solicitando recursos de um servidor remoto (lado servidor).
Dentre as estratégias para essa troca de recursos entre as camadas distintas, temos IFrame, XHR e o Scripttag.
IFrame era uma técnica muito comum na era pré-ajax, mas que causava vários problemas, além da complexidade desnecessária e natureza gambiarrosa. Um dos problemas da técnica era quando se perdia a referência entre os frames e as páginas que os evocam (acontecia com uma frequência não tão insignificante). Geralmente os frameworks implementam a técnica de IFrame por questão de compatibilidade com browsers mais antigos. Quem não se lembra do escondido.jsp (ou escondido.php, escondido.asp, escondido.etc …)?
Como vimos em um post passado, a técnica de usar o XHR nos proporciona trabalhar com o parsing de XML ou a montagem dinâmica de objetos serializáveis, seja com “Eval” ou usando a capacidade dinâmica da linguagem de definir objetos de forma simples em tempo de execução. Vimos que usar Eval não é bom porque “Eval is Evil“.
A técnica de Scripttag está em alta porque aproveita a própria capacidade do browser para instanciar um trecho de código serializável entre as camadas físicas distintas. A técnica está descrita no Pattern Lazy Loading Javascript ou On-Demand javascript
A técnica consiste em se obter um recurso do servidor em forma de texto, mas já formatado como um código (entidade) javascript e adicionar esse trecho na seção head da página, fazendo com que o próprio Browser instancie como se estivesse lendo a página na carga inicial. Vejamos:
function JSONRequest(url) { var head = document.getElementsByTagName("head")[0]; var script = document.createElement('script'); script.id = 'TriadworksOnDemand'; script.type = 'text/javascript'; script.src = url; head.appendChild(script) } function montaGrid(usuarios) { //aguarda um array de usuarios for(var x in usuarios) { //pega usuarios[x]... } } function pesquisar(id) { var url = 'http://server_path/usuario/'+id +"/?callback="+montaGrid; JSONRequest(url); } pesquisar(101);
Observe que criamos uma função chamada JSONRequest, que basicamente pega uma url e adiciona dinamicamente na seção head da página. Essa url é uma saída texto pelo servidor no formato JSON, utilizando o modelo REST para obter um recurso, ou seja, o servidor responde com um objeto serializável no endereço /usuario/id porque ele reconhece que as requisições a esse endereço são lógicas CRUD para a captura do recurso “usuário”. Passo como parâmetro uma variável chamada callback para o servidor renderizar a execução dessa função para ser interpretada assim que o Browser anexar a resposta.
A resposta viria mais ou menos assim:
montaGrid( [ {'id':'101', 'nome':'Christiano', 'sobrenome':'Milfont', 'email':'cmilfont@gmail.com' } ] )
AO executar a função JSONRequest, o código anexa a resposta do servidor na seção Head da página e então o Browser interpreta como se estivesse lendo na carga da página, executando a função montaGrid.
Diferenças entre as abordagens Scripttag e XHR.
| XmlHttpRequest | Dynamic script Tag | |
|---|---|---|
| Compatível com Cross-browser? | Não * | Sim |
| Cross-domain browser security enforced? | Sim | Não |
| Trabalha com HTTP status codes? | Sim | Não (falha com outro código HTTP diferente de 200) |
| Supports HTTP GET and POST? | Sim | Não (Somente GET) |
| Pode receber/enviar HTTP headers? | Sim | Não |
| Pode receber XML? | Sim | Sim (mas embutido na sentença JavaScript) |
| Pode receber JSON? | Sim | Sim (mas embutido na sentença JavaScript) |
| Oferece chamadas síncronas e assíncronas? | Sim | Não (somente assíncronas) |
* - Basicamente poderíamos dizer que é compatível sim, mas com a diferença na implementação. Somente os browsers mais antigos não possuirão o objeto necessário.
Então o uso racional das abordagens vai depender da necessidade de características de cada uma, cada qual possui suas vantagens e desvantagens. Mais em XML.com.
Posted in Ajax, JSON, JavaScript, Web Development, XMLHttpRequest ~ 7 Comments
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:

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.
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) {} } }
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; };
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; } };
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:
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.
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"
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.
Posted in Ajax, JavaScript, XMLHttpRequest ~ 10 Comments