Hace no mucho me encontré con la necesidad de montar una API JSON-RPC que sería llamado desde una página web en un subdominio diferente al del API:

  • Página web: www.patatin.com
  • API JSON-RPC: api.patatin.com

Cómo la mayoría ya sabréis, los navegadores limitan las llamadas AJAX al mismo subdominio de la página web que las realiza, no siendo posible realizar llamadas AJAX fuera de este subdominio. Esto se hace por motivos de seguridad. Forma parte de lo que se conoce como same-origin policy.

Con el advenimiento de la nueva Web basada en APIs, es cada vez mas frecuente encontrarse con escenarios en los que la same-origin policy resulta demasiado restrictiva. Es por ello que desde hace algún tiempo vienen utilizándose diferentes técnicas para superar las limitaciones impuestas por la same-origin policy.

Para el caso que nos ocupa, que implica realizar llamadas AJAX desde un subdominio distinto, existen varias técnicas posibles, como JSONP, pero yo me centraré en la que creo que tiene mas futuro, ya que viene impulsada por el W3C : CORS (Cross-origin resource sharing)

CORS consiste en una especificación estandarizada que añade nuevas cabeceras al protocolo HTTP. Estas cabeceras permiten al servidor ofrecer sus recursos a los subdominios de origen permitidos. Los navegadores deben soportar estas nuevas cabeceras y respetar las retricciones establecidas. Para evitar algunos efectos colaterales de utilizar diferentes métodos en las peticiones, el navegador debe comprobar cada petición utilizando una llamada con el método HTTP OPTIONS, y una vez obtenida la aprobación del servidor, enviar la llamada con el método necesario. Así mismo, los servidores también pueden notificar cuando es necesario presentar credenciales para el envío de una petición.

En nuestro caso concreto, queremos utilizar un servicio JSON-RPC ya existente, así que deberemos de parchear en el lado del servidor, asegurándonos de que se envían las cabeceras adecuadas. En PHP:

$referer_parts=parse_url($_SERVER[‘HTTP_ORIGIN’]);
$origin=$referer_parts[‘scheme’].»://».$referer_parts[‘host’];
header(«Access-Control-Allow-Origin: $origin»);
header(«Access-Control-Allow-Credentials: true»);
header(«Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept»);
header(«Vary: Origin»);

Así mismo, deberemos parchear en el lado del cliente, y asegurarnos de que la llamada AJAX incluya las cabeceras adecuadas. Si se está usando JQuery, deberéis añadir a los parámetros de la llamada AJAX:

$.ajax({

xhrFields: {withCredentials: true },

});

Realmente no termino de entender la necesidad de «withCredentials» en ambos lados (cliente y servidor), ya que no estoy usando ningún tipo de credencial para autentificar al cliente. Sin embargo, no he conseguido que funcione sin ponerlo. Si alguno tiene información al respecto, agradecería que la compartiese.