Requests Ajax com Cross-Origin Resource Sharing (CORS) entre Sencha Touch e ExtJS e Backend
Oi pessoal,
Muitas pessoas às vezes perguntam como uma aplicação que está em um dominio1.com fazer requests Ajax para o dominio2.com ou até mesmo subdomínios do mesmo domínio.
A resposta que o Ext JS e Sencha Touch tem para isso é usar o proxy JsonP, onde você faz um request cross-domain e consegue ler um JSON como resposta. Nesse caso um script javascript será adicionado automaticamente na página para que essa leitura seja possível. Mas o JsonP fazer apenas requests GET, ou seja, só é possível ler dados.
Com uma requisição GET também é possível enviar parâmetros na url, mas como você vai fazer login passando usuário e senha na própria URL (http://dominio1.com?user=loiane&senha=123456)? Não dá né gente!?
Será que é possível então fazer requests AJAX usando GET, POST ou até mesmo REST (GET, POST, PUT, DELETE) para domínios diferentes (cross-domain)?
É possível sim e a resposta é o CORS (Cross-Origin Resource Sharing).
Nesse caso, quando a gente usa CORS precisamos mudar apenas o backend para que este aceite requisições cross-origin. No Ext JS ou Sencha Touch não precisamos fazer nada, vamos usar um proxy Ajax ou Rest (o que preferir) normalmente.
Para adicionar o CORS no backend é muito simples. Nessa página tem todos os detalhes: http://enable-cors.org/
No PHP por exemplo, basta adicionar o seguinte código no início do código de cada arquivo PHP que irá aceitar requisições cross-origin:
<?php
header('Access-Control-Allow-Origin: *');
?>Se você usa Java ou Python, pode olhar os seguintes links:
- Java: http://software.dzhuvinov.com/cors-filter.html (esse filtro é ótimo, uso bastante!)
- Python: https://github.com/monsur/cors-python
- Mais infos: http://enable-cors.org/resources.html
É importante saber também que nem todos os browsers suportam CORS: http://enable-cors.org/client.html
Ok, pode nos mostrar um exemplo Loiane pra ficar mais claro?
Claro que sim! :)
Vou usar o esse exemplo como base, que é um CRUD que já usei algumas vezes aqui no blog.
Se você executar locamente vai rodar tranquilo.
Agora, vou retirar a parte PHP e vou fazer deploy em outro servidor/computador e vou executar o Ext JS de um computador. Para melhor exemplificar, vou executar o código Ext JS no código do meu laptop e o PHP vai ficar deployado no meu desktop:
Meu desktop - computador 01:
Meu notebook - computador 02:
Como os códigos cliente e servidor estão separados, na Store do ExtJS preciso atualizar a url, já que o acesso ao php não é mais local. No meu caso ficou assim:
api: {
create: 'http://192.168.0.14/blog/sencha-cors-comp01/extjs4-crud-mvc/php/criaContato.php',
read: 'http://192.168.0.14/blog/sencha-cors-comp01/extjs4-crud-mvc/php/listaContatos.php',
update: 'http://192.168.0.14/blog/sencha-cors-comp01/extjs4-crud-mvc/php/atualizaContato.php',
destroy: 'http://192.168.0.14/blog/sencha-cors-comp01/extjs4-crud-mvc/php/deletaContato.php'
}Se tentar executar agora, não vai funcionar e o Ext JS vai lançar uma exception dizendo que não consegue fazer esse request e/ou o servidor não consegue processar:
Note que o código onde está o código ExtJS é localhost (127.0.0.1) e estou tentando fazer request para 192.168.0.14, ou seja, domínios diferentes.
Agora vamos voltar no código PHP e adicionar o Access-Control-Allow-Origin: * - na verdade, no site do CORS fala que basta adicionar o header, mas isso não procede. Para que o seu código trate o CORS de maneira correta no PHP, é necessário um pouco mais que isso! Criei um arquivo novo chamado enableCORS.php com o seguinte conteúdo:
<?php
function enableCORS() {
// Allow from any origin
if (isset($_SERVER['HTTP_ORIGIN'])) {
header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Max-Age: 86400'); // cache for 1 day
}
// Access-Control headers are received during OPTIONS requests
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))
header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
exit(0);
}
return true;
}
?>E no código para listar os contatos, por exemplo, o início do arquivo ficaria assim:
<?php
include("enableCORS.php");
enableCORS();
//chama o arquivo de conexão com o bd
include("connect.php");
$start = $_REQUEST['start'];
$limit = $_REQUEST['limit'];
$queryString = "SELECT * FROM contact LIMIT $start, $limit";
...E vamos tentar novamente:
Agora funciona! E basta fazer o mesmo para todos os arquivos PHP para que o CRUD funcione como esperado.
Se a gente olhar os detalhes do request, vamos ver as informações do response e ver que o request foi feito usando CORS:
O mesmo se aplica a alguma app Sencha Touch - ou até mesmo requisição Ajax com JQuery.
Caso queria conferir o código completo usado nesse post, segue o exemplo de CRUD com CORD habilitado: https://github.com/loiane/sencha-touch-extjs-CORS
Até a próxima! :)






