Front End

12 set, 2012

Cross-Origin Ajax com CORS

Publicidade

Não há dúvida de que o Ajax é uma das tecnologias web disponíveis mais interessantes, úteis e necessárias para desenvolvedores de front-end. Infelizmente, é também uma das mais restritivas – especialmente quando o assunto é reunir conteúdo de outros domínios. Os desenvolvedores web não são nada se não persistentes, por isso vou apresentar uma variedade de maneiras para contornar as restrições de cross-origin, incluindo JSONP, proxies do lado do servidor  feitos com PHP, proxy ProxyPass, transportes Flash, usos criativos iFrame e muito mais. O que muitos desenvolvedores não sabem é que existe uma especificação W3C chamada“Cross-Origin Resource Sharing”, ou “CORS”, que fornece um padrão para solicitações cross-origin do Ajax com hassle mínimo.

Como a API do Ajax é diferente entre os navegadores e a maioria dos desenvolvedores usa um kit de ferramentas do JavaScript, os exemplos mostrados neste artigo usarão o framework MooTools JavaScript. O CORS vai funcionar com qualquer framework JavaScript, já que a filosofia central e o código seja configurado no servidor, e não no lado do cliente. Devido a sua popularidade, o Apache será utilizado nos exemplos de configuração do lado do servidor.

Solicitações básicas do Ajax

Cada um dos frameworks do JavaScript abstrai objetos XMLHttpRequest (ou, no caso do Internet Explorer, ActiveXObject ou Microsoft.XMLHTTP) para fazer requisições do Ajax. Esses pedidos apresentam uma URL e podem conter cabeçalhos extras, dados, tipos diferentes de solicitação (GET, POST, PUT ou DELETE), e muito mais. Um pedido Ajax básico seria mais ou menos assim:

// Create a new Ajax request
var request = new Request.JSON({
// The URL to get content from
url: "/countries.json",
// The success callback
onSuccess: function(countries) {
// Log out the content
console.log("The countries are: ", countries);
}
}).send(); // Send the request

A URL no pedido acima é local; countries.json está localizado dentro de uma mesma origem. E se a gente, ainda assim, tentar obter tweets do Twitter?

// Create a new Ajax request
var request = new Request.JSON({
// The URL to get content from
url: "http://twitter.com/statuses/user_timeline/davidwalshblog.json",
// The success callback
onSuccess: function(tweets) {
// Log out the content
console.log("The tweets are: ", content);
}
}).send(); // Send the request

A solicitação para o Twitter irá falhar porque o destino solicitado, twitter.com, não é o mesmo que o da origem. Cada navegador fornece a sua própria mensagem de erro; o Chrome irá avisá-lo com: XMLHttpRequest cannot load http://twitter.com/statuses/user_timeline/davidwalshblog.json. Origin http://davidwalsh.name is not allowed by Access-Control-Allow-Origin.

No caso do Twitter, poderíamos utilizar um pedido JSONP, mas o problema com ele é que o servidor de destino deve suportá-lo. Mesmo que o destino suporte o JSONP, você não pode fazer um POST na URL ou enviar cabeçalhos de requisição específicos. Como podemos resolver esse enigma? Com o CORS, claro.

Implementando CORS

O CORS permite solicitações cross-origin com um pouco de exagero. Uma vez que o servidor de destino for o órgão no controle e “em risco”, ele deve ser configurado com os cabeçalhos adequados e configurações de segurança. Alguns dos cabeçalhos principais incluem:

Access Control-Allow-Origin

A URL específica ou * que identifica que domínio (s) pode fazer solicitações cross-origin para esse servidor (destino). (* é um valor de configuração indesejável, uma vez que permite que toda e qualquer origem faça solicitações para o servidor.)

Access-Control-Allow-Methods

Uma lista separada por vírgulas de métodos de solicitação permitidos.

Access-Control-Allow-Headers

Uma lista separada por vírgula de cabeçalhos de requisição permitidos.

Supondo que um site está hospedado em um servidor Apache, um host a virtual pode ser configurado da seguinte forma:

<VirtualHost *:80>
DocumentRoot "/path/to/website/root"
ServerName domain.tld
Header set Access-Control-Allow-Origin http://example.com
Header set Access-Control-Allow-Methods POST,GET
Header set Access-Control-Allow-Headers X-Authorization,X-Requested-With
</VirtualHost>

A configuração acima apenas permite pedidos remotos a partir de http://example.com, o tipo de pedido só pode ser POST ou GET, e permitiu que os cabeçalhos fossem X-Authorization and X-Requested-With.

Se você pretende permitir que qualquer um faça requisições Ajax para o seu domínio e com qualquer tipo de pedido, você pode optar por esta configuração:

<VirtualHost *:80>
DocumentRoot "/path/to/website/root"
ServerName domain.tld
Header set Access-Control-Allow-Origin *
Header set Access-Control-Allow-Methods POST,GET,DELETE,PUT,OPTIONS
Header set Access-Control-Allow-Headers X-Authorization,X-Requested-With
</VirtualHost>

Com o servidor de destino configurado, podemos enviar solicitações cross-origin de onde quer a gente queira:

// Create a new Ajax request
var request = new Request({
// The URL to get content from
url: "http://example.org/content.php",
// The success callback
onSuccess: function(content) {
// Log out the content
console.log("The content is: ", content); // Works!
}
}).send(); // Send the request

A grande questão é: “quais navegadores implementaram a especificação CORS?” A maioria deles, na verdade. Firefox 3.5+, Safari 4+, Chrome 3+, e IE9+. O IE8 não suporta o CORS padrão, mas tem um objeto XDomainRequest, e o Opera ainda não implementou CORS. Esse nível atual de suporte, no entanto, faz do CORS uma opção viável para muitos sites. Se você gerencia um serviço web ou simplesmente deseja improvisar com estratégias Ajax, mantenha o CORS em mente; eu tenho uma suspeita de que ele vai desempenhar um grande papel no futuro do desenvolvimento web.

***

Texto original disponível em http://phpadvent.org/2011/cross-origin-ajax-with-cors-by-david-walsh