jueves, 2 de agosto de 2012

Ajax Cross-Domain con jQuery y JSONP

En lenguajes de programación del lado del servidor (como PHP), es muy común obtener datos de un servidor remoto a través de Web Services o funciones FTP.

No obstante, uno de los aspectos de seguridad más importantes que manejan los navegadores Web modernos, tiene como objetivo impedir que scripts del lado del cliente (por ejemplo Javascript) puedan obtener o establecer información ubicada en un servidor (dominio) distinto al que aloja el script desde donde se hace la petición a través de Ajax. Me refiero a la Política del Mismo Origen o Same Origin Policy.

Incluso, la restricción aplica si se trata de un subdominio, protocolo o puerto distinto. Por ejemplo, si me encuentro en
http://www.servidorUNO.com
, no podré acceder a ninguno de los siguientes orígenes:

http://www.servidorDOS.com      /* Dominio diferente */  

https://www.servidorUNO.com     /* Protocolo diferente */

http://www.servidorUNO.com:81   /* Puerto diferente */   


Sin embargo, utilizando JSONP en una petición Ajax es posible obviar esta prohibición fácilmente.

El patrón JSONP (JSON con relleno) es un complemento del formato de datos JSON con el que se puede obtener información entre dominios distintos, la cual es devuelta por el servidor remoto encapsulada en una función Javascript. Es decir, se obtiene un JSON generado dinámicamente, pero envuelto dentro de una invocación a una función Javascript que procesará los datos retornados por el servidor. Veamos paso a paso cómo programar este método y las variantes que nos ofrece jQuery.

En primer lugar, tenemos el código del script alojado en el servidor remoto, que armará dinámicamente la respuesta en formato JSON (encapsulada en una función Javascript) a partir de la validación del parámetro callback que veremos más adelante.

Código servicioRemoto.php

PHP
<?php

if ($_GET['ajaxCrossParam'] == 1) {

    $info = array();
    $info['id'] = '10';
    $info['mensaje'] = 'Ajax Cross-Domain con jQuery';
    
    if (isset($_GET['callback'])) {
        echo $_GET['callback'] . '( ' . json_encode($info) . ' )';
    } else {
        echo 'callbackEjercicio( ' . json_encode($info) . ' )';
    }

}
Por otra parte, alojado en el servidor donde estamos ubicados, tenemos la interfaz HTML del ejercicio que se compone de un enlace y una división vacía donde se mostrará la información retornada.

Código ejercicio.html

HTML
<!DOCTYPE>
<html>
    <head>
        <meta charset="utf-8" />
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
        <script src="ejercicio.js"></script>
    </head>
    <body>
        <a href="#" id="info">Obtener datos remotos</a>
        <div class="info"></div>
    </body>
</html>
A continuación, les mostraré las diferentes opciones que suministra jQuery para hacer las peticiones Ajax con JSONP.

Opción 1:

A través de la función getJSON, enviando el parámetro
callback=?
, que jQuery interpretará automáticamente como una petición JSONP a un dominio diferente. La información recibida en formato JSON será procesada por getJSON cuando los datos sean cargados satisfactoriamente. La respuesta tendrá un aspecto parecido a:
jQuery1720631428341654198_1344210097413( {"id":"10","mensaje":"Ajax Cross-Domain con jQuery"} )


Notemos que los datos JSON
{"id":"10","mensaje":"Ajax Cross-Domain con jQuery"}
vienen encapsulados en la función
jQuery1720631428341654198_1344210097413()
, creada automáticamente por jQuery.

Código ejercicio.js

JS
jQuery(document).ready(function(){
    jQuery("#info").click(function(){
        jQuery.getJSON(
            "http://www.servidorDOS.com/servicioRemoto.php?callback=?",
            {ajaxCrossParam: "1"},
            function(data){
                jQuery("div.info").show();
                jQuery("div.info").append("<br/>id: " + data.id + "<br/>");
                jQuery("div.info").append("mensaje: " + data.mensaje + "<br/>");
            }
        );
    });
});

Opción 2:

De nuevo con la función getJSON, enviando el parámetro
callbackEjercicio=?
, que será la función Javascript encargada de procesar los datos recibidos en formato JSON. Aquí es importante aclarar que el nombre del parámetro debe ser conocido por el script del servidor remoto, puesto que se trata de la función que encapsulará el JSON a entregar. La respuesta se parecerá a:
callbackEjercicio( {"id":"10","mensaje":"Ajax Cross-Domain con jQuery"} )


Esto quiere decir que el servidor toma el nombre de la funcion recibida en la URL y decide el valor de su parámetro en formato JSON.

Código ejercicio.js

JS
function callbackEjercicio(data) {
    jQuery("div.info").show();
    jQuery("div.info").append("<br/>id: " + data.id + "<br/>");
    jQuery("div.info").append("mensaje: " + data.mensaje + "<br/>");
}

jQuery(document).ready(function(){
    jQuery("#info").click(function(){
        jQuery.getJSON(
            "http://www.servidorDOS.com/servicioRemoto.php?callbackEjercicio=?",
            {ajaxCrossParam: "1"}
        );
    });
});

Opción 3:

Esta vez por medio de la función ajax, estableciendo el elemento
dataType: "jsonp"
. Los datos recibidos en formato JSON serán procesados en el evento
success:
cuando esta se haya cargado correctamente. La respuesta tendrá un aspecto parecido a la de la opción 1.

Aquí jQuery pone automáticamente el parámetro
callback=?
al final de la URL solicitada cuando le decimos que el tipo de dato esperado es JSONP.

Código ejercicio.js

JS
jQuery(document).ready(function(){
    jQuery("#info").click(function(){
        jQuery.ajax({
            url: "http://www.servidorDOS.com/servicioRemoto.php",
            data: "ajaxCrossParam=1",
            type: "GET",
            dataType: "jsonp",
            success: function(data){ 
                jQuery("div.info").show();
                jQuery("div.info").append("<br/>id: " + data.id + "<br/>");
                jQuery("div.info").append("mensaje: " + data.mensaje + "<br/>");
            }
        });
    });
});

Opción 4:

A través de la función ajax, estableciendo el elemento
dataType: "jsonp"
y enviando el parámetro
callbackEjercicio=?
que será la función encargada de procesar los datos recibidos en formato JSON. La respuesta tendrá un aspecto parecido a la de la opción 2.

Código ejercicio.js

JS
function callbackEjercicio(data) {
    jQuery("div.info").show();
    jQuery("div.info").append("<br/>id: " + data.id + "<br/>");
    jQuery("div.info").append("mensaje: " + data.mensaje + "<br/>");
}

jQuery(document).ready(function(){
    jQuery("#info").click(function(){
        jQuery.ajax({
            url: "http://www.servidorDOS.com/servicioRemoto.php?callbackEjercicio=?",
            data: "ajaxCrossParam=1",
            type: "GET",
            dataType: "jsonp"
        });
    });
});
En síntesis, debemos realizar la petición Ajax con JSONP cumpliendo con los factores especificados en el servidor remoto (API) del que deseamos obtener o establecer datos. Entre estos factores, tenemos el nombre de la función Javascript que procesará los datos, además de otros parámetros requeridos para diferentes fines. La información retornada es una ejecución a la función Javascript enviada, junto con sus parámetros, armados por el servidor remoto en formato JSON válido.

Espero sus comentarios y deseo que haya sido de muchísima utilidad. Hasta la próxima!!

1 comentario:

  1. y si quiero enviar un parametro traido de un input como lo agregaria en estas funciones?

    desde el php lo recibo con $_POST o $_GET pero no se como hacer para que se envie en el mismo evento

    ResponderEliminar