sábado, 3 de julio de 2010

Resolviendo llamados AJAX entre dominios distintos

Esta semana tuve la necesidad de consumir servicios JSON a través de AJAX, el problema es que esos servicios estaban en otro host. Buscando en internet, llegué a que el tema de realizar llamadas a AJAX entre distintos dominios no funcionaba directamente, ya que era una gran brecha de seguridad permitir hacer esto en HTTP. Luego de un rato de darme la cabeza contra el teclado, decidí hacerlo de esta forma.

Digamos que tengo una vista (una página) desde la que necesito consumir el servicio JSON invocando una determinada URL por AJAX, con Prototype esto sería algo así (esta invocación falla por hacerse a un dominio distinto al local):

Event.observe(window, 'load', function() {

   new Ajax.Request('http://www.otrohost.com/servicio', {
      method: 'get',
      onLoading: function(res) {
         ....
      },
      onSuccess: function(res) {
         var json = res.responseJSON; // resultado del servicio JSON
         ....
      }
   });
});

Sustituyendo la url destino del llamado AJAX por una url local, quien atiende la llamada es la acción de un controlador de Yupp, entonces se puede hacer que esa acción sea la que haga el llamado al servicio JSON en http://www.otrohost.com/servicio y devuelva a la vista el resultado.

El controlador tendrá este aspecto (archivo: /components/xxx/controllers/components.xxx.controllers.ServicioController.class.php):

YuppLoader::load('core.http', 'HTTPRequest');

class ServicioController extends YuppController {

   public function getJSONAction()
   {
      $req = new HTTPRequest();
      $req->setTimeOut( 5 );
      $res = $req->HTTPRequestGet('http://www.otrohost.com/servicio');

      // La respuesta
      $json = $res->getBody();
      
      // Devuelve la respuesta a la vista
      header('Content-Type: application/json');
      return $this->renderString( $json );
   }
}


Así logramos pedirle a un controlador local que haga un pedido HTTP al servicio JSON remoto y que devuelva el objeto JSON a la vista local desde la que partió el pedido AJAX original. El javascript en la vista con la invocación al controlador local quedaría así:

Event.observe(window, 'load', function() {

   new Ajax.Request('<?php echo h('url', array('component'=>'xxx', 'controller'=>'servicio', 'action'=>'getJSON'); ?>', {
      method: 'get',
      onLoading: function(res) {
         ....
      },
      onSuccess: function(res) {
         var json = res.responseJSON; // resultado del servicio JSON local
         ....
      }
   });
});

Así con pocas líneas de código podemos resolver un problema que tenemos frecuentemente, sobre todo cuando necesitamos consumir APIs externas con servicios JSON o XML.

No hay comentarios:

Publicar un comentario