porque-meu-app-nao-carrega-dados-externos-lidando-com-cors-e-origins-externas

Hoje temos uma rápida, porém essencial dica: Por que um app não carrega dados externos? Como resolver o Cross Origin Resource Sharing (CORS) policy error?

Se você, meu amigo, minha amiga, desenvolvedor já precisou consumir dados estando fora do servidor (Por exemplo, consumir uma API REST que sirva o conteúdo em JSON à partir de uma aplicação com AngularJS ou Ionic Framework), então é provável que tenha se deparado com erro do CORS.

Ao fazer o deploy do webservice para um servidor remoto (de desenvolvimento ou produção), o frontend misteriosamente pára de funcionar.

Todas aquelas lindas requisições XHR abstraídas em $.ajax, ou nos $http e $resource da vida, ou qualquer outra forma de pegar os dados da sua API páram de funcionar quando os rescursos do servidor e o front já não estão na mesma oirigin

CORS

Pra resolver, comece identificando a causa


Primeiro, temos de entender o que significa CORS. Cross Origin Resource Sharing é o quando precisamos interagir com recursos fora do servidor. Por medidas de segurança, navegadores desktop , e algumas versões de sistemas operacionais Android e iOS exigem que seja declarado no servidor de origem os clients autorizados a consumir os dados.

Vou comentar agora duas formas difernetes, sendo uma para desenvolvimento, e outra mais adequada para produção.
 

Quebrando um galho:

Enganando seu navegador para burlar CORS. (Bypassing CORS)


Bom, como para permitir a conexão em diferentes origens é necessário apenas um Header autorizando isso explicitamente, existe uma forma bem simples à lá gambiarration, que é interceptar as requisições antes do navegador, inserindo o Header permissivo nelas.

Isso pode ser feito para Google Chrome, com Esta extensão maneira

Interceptando com um proxy


Você pode criar um proxy para enviar o header. Sorte que sua que o camarada @suissa já fez isso pra vc:

http://cors-server.getup.io/url/:SUAURLPARACORS permite que vc insira :SUAURLPARACORS alí na url e tenha o header adicionado à sua requisição.

NÃO OBSTANTE QUEBRAR O SEU GALHO, ainda tá OpenSource este pequeno server: https://github.com/suissa/cors-server

 

O jeito certo

declarando no servidor os clients autorizados à consumir os dados


O erro de segurança do CORS é justamente por que o navegador quer, antes de consumir os dados, ter certeza que o servidor está ciente que ele está fazendo isso.

É necessário declarar no header Access-Control-Allow-Origin do server os clients que tem permissão para consumir os dados

Definimos as origins permitidas com seu hostname, ou wildcards, por exemplo:

  • localhost
  • 192.189.200.**

Para um wildcard geral e genérico (não muito indicado), usamos *. Veja algumas formas de definir este cabeçalho:

 

No Apache Web Server

Usando headers para evitar problemas com CORS


No servidor Apache podemos usar um arquivo .htaccess com o seguinte conteúdo:

.htaccess [Setando o header Access-Control-Allow-Origin para *]
1
Header set Access-Control-Allow-Origin "*"

 

Com nGinx Server

setando header server-wide no nGinx


No nginX (o servidor que vc precisa conhecer, se ainda não conhece), a configuração site-wide pode ser feita diretamente no arquivo .vhost.

seudominio.vhost
1
location / {
  add_header 'Access-Control-Allow-Origin' '*';
}

 

Com PHP

setando headers diretamente com PHP, para evitar problemas de CORS


Caso as configurações de segurança do seu servidor permitam, é possível fazer pelo PHP, mesmo sem acesso ao .htacces.
Lembrando que definir os header via php deve ser sempre feito em uma vez só, preferencialmente em um mesmo arquivo, para evitar erros de header already sent.

1
2
3
<?php
header("Access-Control-Allow-Origin: *");
?>

 

Com NodeJS (Express.js)

setando headers com NodeJS, para que a API sirva o cabeçalho necessário


Basta criar um middleware que adicione à response o header. Isso é feito com res.header().

1
2
3
4
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
next();
});

 

Para ASP.net

se vc usa asp.net, pode fazer assim para definir os headers do seu servidor*


Se não tiver acesso às configurações do ISS, pode tentar definir o header diretamente no seu código:

arquivo.asp
1
Response.AppendHeader("Access-Control-Allow-Origin", "*");

Outras opções para resolver problema de CORS, server side:

Para ver uma boa lista com dicas de como configurar os Headers necessários para seu servidor servir o conteúdo sem esbarrar no CORS Policy error, dê uma conferida no http://enable-cors.org

 

##Para Phonegap/Cordova/Ionic Framework:

Declarando no Config.XML da sua aplicação PhoneGap/Cordova/Ionic as Origins permitidas.


Para versões mais recentes do Android (à partir do kitkat, eu acho :P ), trounou-se necessário declarar permissão de acesso à recursos externos no arquivo config.xml.

Antes isso não era obrigatório, então era possível usar o tweak da extensão do Chrome durante o desenvolvimento, e depois apenas empacotar seu .apk que tudo ficaria bem.

Hoje, basta instalar o plugin Corvoda Plugin WhiteList via terminal:

1
(Cordova)
$ cordova plugin add https://github.com/apache/cordova-plugin-whitelist
(Phonegap)
$ phonegap plugin add https://github.com/apache/cordova-plugin-whitelist
(Ionic Framework)
$ ionic plugin add https://github.com/apache/cordova-plugin-whitelist

E, uma vez instalado, declarar no arquivo CONFIG.XML do projeto as origens permitidas.

São 2 parâmetros: access origin e allow-navigation. O Access origin permite interação com a url ou domínio, ou wildcard inserido. O Allow-navigation especifica quais domínios ou sites/wildcard podem ser abertos por um link da sua aplicação.

(projetoMobile/config.xml)
1
2
<access origin="*://*.urldaSuaAPI.com/*"/>
<allow-navigation href="*://*.linksExternosPermitidosViaApp.com/*"/>

Além da declaração do header no server-side, declarar access origin no CONFIG.XML do seu APP pode ser necessário

 

Resumindo e Concluindo os paranauê

Então é o seguinte: CORS é o nome da requisição feita de locais/servidores diferentes. Quando vc está local e baixa dados do localhost, não há Cors. Pois não fere a same origin policy, dos navegadores.

Quando é feita uma requisição externa, o servidor deve declarar permissão para a origem, ou wildcard, permitindo o acesso.

Caso isso não seja possível em uma das 20 formas diferentes em linguagens diferentes e ambientes distintos, vc pode sempre usar uma extensão que intercepte suas requisições e adicione o Access-Control-Allow-Origin à elas.