Uno de los problemas con los que nos encontramos al trabajar con Ajax, es la limitación a trabajar siempre bajo el mismo dominio. Para entendernos, desde https://www.anieto2k.com no puedo acceder mediante una petición Ajax a un contenido en http://www.google.com.
Debido a las peticiones por parte de la comunidad de desarrolladores se creó una estandarización para permitir extender el objeto XMLHttpRequest()
con la capacidad de permitir peticiones entre diferentes dominios, permitiendo una mejor integración entre servicios online.
Safari4, Google Chrome 2 y ahora Firefox 3.5, ya implementan dicha mejora y nos permite trabajar con ella. Por otro lado Microsoft, en otro mundo, desarrolla XDomainRequest()
que permite realizar exactamente lo mismo en la última versión de su navegador (la 8.0).
¿Como funciona?
La idea básica es muy sencilla, el nuevo objeto XMLHttpRequest()
envia una nueva cabecera al servidor destino
Access-Control-Allow-Origin: http://servidor.destino
Y este, permite el acceso o no indicándo una cabecera nueva en la respuesta:
//PHP
<?php header('Access-Control: allow <*>'); ?> //Permitimos todos
<?php header('Access-Control: deny <*>');?> //Denegamos todos
<?php header('Access-Control: allow <mozilla.org>');?> //Permitimos solo mozilla.org
<?php header('Access-Control: allow <mozilla.org> exclude <developer.mozilla.org>');?> //Permitimos mozilla.org y denegamos developer.mozilla.org
<?php header('Access-Control: allow <developer.mozilla.org:80> method GET, POST');?> //Permitimos developer.mozilla.org para el puerto 80 en los métodos GET y POST
//XML
<?access-control allow="*"?> //Permitimos todos
<?access-control deny="*"?> //Denegamos todos
<?access-control allow="mozilla.org"?> //Permitimos solo mozilla.org
<?access-control allow="mozilla.org" exclude="developer.mozilla.org"?> //Permitimos mozilla.org y denegamos developer.mozilla.org
<?access-control allow="developer.mozilla.org" method="GET POST"?> //Permitimos developer.mozilla.org para el puerto 80 en los métodos GET y POST
Veamos un ejemplo de la cabecera devuelta al navegador:
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2.0.61
Access-Control-Allow-Origin: http://servidor.destino
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml
Cross-domain && Cross-browser
Como en casi todas las nuevas funcionalidades tenemos que contemplar las posibilidad de que esta no esté disponible en el navegador del usuario, para ello debemos detectarlas y ofrecer una alternativa…
Ejemplo simple de envio por GET
var url = "http://bar.other/publicNotaries/";
if(XMLHttpRequest) {
var request = new XMLHttpRequest();
if("withCredentials" in request) {
// Firefox 3.5 y Safari 4
request.open('GET', url, true);
request.onreadystatechange = handler;
request.send();
} else if (XDomainRequest) {
// IE8
var xdr = new XDomainRequest();
xdr.open("get", url);
xdr.send();
} else {
// Otros navegadores
}
}
En este caso, usaremos como flag el atribute withCredentials
para comprobar que está disponible esta nueva característica en el navegador del usuario.
“Preflighted” Request (No lo he sabido traducir).
Otra opción de la que disponemos es la capacidad de realizar una consulta previa al servidor para comprobar la disponibilidad de la funcionalidad.
var invocation = new XMLHttpRequest();
var url = 'http://bar.other/resources/post-here/';
var body = '<?xml version="1.0"?><person><name>Arun</name></person>';
function callOtherDomain(){
if(invocation) {
invocation.open('POST', url, true);
invocation.setRequestHeader('X-PINGOTHER', 'pingpong');
invocation.setRequestHeader('Content-Type', 'application/xml');
invocation.onreadystatechange = handler;
invocation.send(body);
}
En este caso, estamos enviando una cabecera previa llamada OPTIONS
:
OPTIONS /resources/post-here/ HTTP/1.1
Origin: http://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER
Y el servidor de destino nos devolverá información sobre las capacidades disponibles:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://arunranga.com
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER
Access-Control-Max-Age: 1728000
Posteriormente, devolverá las cabeceras con la respuesta:
POST /resources/post-here/ HTTP/1.1
...
Content-Type: application/xml; charset=UTF-8
X-PINGOTHER: pingpong
...
Esta funcionalidad no está disponible en XDomainRequest()
de Internet Explorer 8.
Envio de Credenciales
Por defecto, las credenciales como Cookies o HTTP Auth, no se envian en la petición XMLHttpRequest(), si necesitamos enviarlos, la nueva implementación nos lo permite con un atributo que hemos visto previamente.
Por defecto, el valor de withCredentials
es false
, así que tendremos que modificarlo antes de realizar la petición.
var request = new XMLHttpRequest();
var url = 'http://bar.other/resources/credentialed-content/';
function callOtherDomain(){
if(request)
{
request.open('GET', url, true);
request.withCredentials = "true";
request.onreadystatechange = handler;
request.send();
}
Otra vez, Internet Explorer 8 y si XDomainRequest()
no permiten hacer esto.
8 comentarios, 0 referencias
+
#