2010-04-01 36 views
64

Sé acerca de la política de dominio AJAX entre dominios. Así que no puedo simplemente llamar "http://www.google.com" a través de una solicitud de HTTP ajax y mostrar los resultados en algún lugar de mi sitio.AJAX llamada de dominio cruzado

he probado con tipoDatos "jsonp", que realmente iba a funcionar, pero me da un error de sintaxis (obviamente porque los datos recibidos no se formatea JSON)

¿Hay alguna otra posibilidad para recibir datos/visualización de un dominio extranjero? iFrames sigue la misma política?

Respuesta

63

La única forma (fácil) de obtener datos entre dominios mediante AJAX es usar un idioma del lado del servidor como el proxy como Andy E. He aquí una pequeña muestra de cómo implementar que el uso de jQuery:

La parte jQuery:

$.ajax({ 
    url: 'proxy.php', 
    type: 'POST', 
    data: { 
     address: 'http://www.google.com' 
    }, 
    success: function(response) { 
     // response now contains full HTML of google.com 
    } 
}); 

Y el PHP (proxy.php):

echo file_get_contents($_POST['address']); 

Tan simple como eso. Solo tenga en cuenta lo que puede o no puede hacer con los datos raspados.

+28

Y sea muy consciente de que tal proxy es un agujero de seguridad severo ... Al menos haga una lista de direcciones aceptables y no solo acepte ciegamente cualquier dirección pasada. Eche un vistazo a un script proxy decente aquí: http://benalman.com/projects/php-simple-proxy/ –

+1

¿Pero no rompe el diseño cuando la página de destino tiene URL no absolutas y enlaces relativos? – Mori

+0

@ChristianStuder ¿Por qué es esto problemático? – John

18

Tendrá que insertar dinámicamente una etiqueta de script en la página que hace referencia a los datos. Usando JSONP, puede ejecutar alguna función de devolución de llamada cuando el script se haya cargado.

La página de la wikipedia en JSONP tiene un ejemplo conciso; la etiqueta script:

<script type="text/javascript" src="http://domain1.com/getjson?jsonp=parseResponse"> 
</script> 

habría devolver los datos JSON envueltos en una llamada a parseResponse:

parseResponse({"Name": "Cheeso", "Rank": 7}) 

(dependiendo de la configuración de la secuencia de comandos getjson en domain1.com)

El código para insertar la etiqueta dinámica sería algo así como:

var s = document.createElement("script"); 
s.src = "http://domain1.com/getjson?jsonp=parseResponse"; 
s.type = "text/javascript"; 
document.appendChild(s); 
+0

¿funcionaría esto solo si recibe datos JSON o también con texto plano o HTML? – jAndy

+1

@jAndy: Esto funcionará solo para datos JSONP (incluida la función de devolución de llamada). –

+0

solo funciona para solicitudes GET. Sin PUT, DELETE o POST. Entonces no hay una interfaz REST. – ProblemsOfSumit

2

JSONP es la mejor opción, en mi opinión. Intente descubrir por qué obtiene el error de sintaxis. ¿Está seguro de que los datos recibidos no son JSON? Entonces, tal vez estés usando el API incorrectamente de alguna manera.

Otra forma podría utilizar, pero no creo que se aplica en su caso, es tener un marco flotante en la página de la cual src está en el dominio al que desea llamar. Haga que haga las llamadas por usted, y luego use JS para comunicarse entre el iFrame y la página. Esto omitirá el dominio cruzado, pero solo si puede tener el src del iFrame en el dominio al que desea llamar.

+1

@Nir: Obtiene el error de sintaxis porque está obteniendo HTML, no JSON. Esto nunca funcionará con JSONP :-) –

11

Desafortunadamente (o afortunadamente) no. La política de dominios cruzados está ahí por una razón, si fuera fácil de evitar, entonces no sería muy efectiva como medida de seguridad. Además de JSONP, la única opción es proxy the pages using your own server.

Con un iframe, están sujetos a la misma política. Por supuesto, puede visualizar los datos de un dominio externo, simplemente no puede manipularlo.

+0

¿a qué te refieres con "simplemente no puedes manipularlo"? No puede cargar algunos datos en un iFrame y leer esos datos a través de un selector de jQuery, por ejemplo. – jAndy

+4

@jAndy: No, el acceso está bloqueado al 99% del DOM cuando se accede a documentos en diferentes dominios. La mensajería entre documentos es posible (con HTML5/navegadores modernos), pero debe ser implementada por ambas partes. –

4

después de hacer algunas investigaciones, la única "solución" a este problema es llamar:

if($.browser.mozilla) 
    netscape.security.PrivilegeManager.enablePrivilege('UniversalBrowserRead'); 

esto va a pedir a un usuario si permite que una página web para continuar. Después de confirmarlo, todas las llamadas ajax independientemente de su tipo de datos se ejecutarán.

Esto funciona para navegadores mozilla, en IE < 8, un usuario tiene que permitir una llamada de dominio cruzado de una manera similar, alguna versión debe configurarse dentro de las opciones del navegador.

chrome/safari: No encontré una bandera de configuración para esos navegadores hasta el momento.

usando JSONP como tipo de datos sería bueno, pero en mi caso no sé si un dominio necesito para acceder admite datos en ese formato.

Otra posibilidad es utilizar HTML5 postMessage que también funciona con dominios cruzados, pero no puedo permitir que mis usuarios sean condenados a navegadores HTML5.

+14

no está condenando a sus usuarios a los navegadores HTML5, los está convirtiendo en un servicio :-) –

-3

Me enfrenté al mismo problema durante 2 días y encontré la solución, y es elegante después de buscar en Google mucho. Necesitaba xss Ajax para algunos clientes de widgets que extraen datastream de los sitios web de los niveles en mi aplicación Rails. here's how I did.

4

Utilizo este código para la llamada de ajax de dominio cruzado, espero que ayude a más de uno aquí. Estoy usando librería Prototype y se puede hacer lo mismo con jQuery o Dojo o cualquier otra cosa:

Paso 1: crear un nuevo archivo js y poner dentro de esta clase, lo llamé xss_ajax.js

var WSAjax = Class.create ({ 
    initialize: function (_url, _callback){ 
     this.url = _url ; 
     this.callback = _callback ; 
     this.connect() ; 
    }, 
    connect: function(){ 
     var script_id = null; 
     var script = document.createElement('script'); 
     script.setAttribute('type', 'text/javascript'); 
     script.setAttribute('src', this.url); 
     script.setAttribute('id', 'xss_ajax_script'); 

     script_id = document.getElementById('xss_ajax_script'); 
     if(script_id){ 
      document.getElementsByTagName('head')[0].removeChild(script_id); 
     } 

     // Insert <script> into DOM 
     document.getElementsByTagName('head')[0].appendChild(script); 
    }, 
    process: function (data){ 
     this.callback(data) ; 
    } 

}) ; 

Esta clase crea un elemento de script dinámico que src atribuye a su proveedor de datos JSON (JSON-P, de hecho, ya que su servidor distante debe proporcionar los datos en este formato :: call_back_function (// json_data_here) :: entonces cuando se crea la etiqueta de script su JSON será evacuado directamente como una función (hablaremos sobre pasar el nombre del método de devolución de llamada al servidor en el paso 2), el concepto principal detrás de esto es que las secuencias de comandos como img no se preocupan por las restricciones de SOP.

Paso 2: En cualquier página HTML donde se quiere tirar de la JSON de forma asíncrona (llamamos a esto :-) AJAJ ~ Asynchronous JavaScript + JSON en lugar de AJAX que utilizan el objeto XHTTPRequest) hacer, como a continuación

//load Prototype first 
//load the file you've created in step1 


var xss_crawler = new WSAjax (
    "http://your_json_data_provider_url?callback=xss_crawler.process" 
, function (_data){ 
      // your json data is _data and do whatever you like with it 
     }) ; 

D '¿recuerdas la devolución de llamada en el paso 1? así que lo pasamos al servidor y devolverá el JSON embebido en ese método, por lo que en nuestro caso el servidor devolverá un código de JavaScript evarable xss_crawler.process (// the_json_data), recuerde que xss_crawler es una instancia de la clase WSAjax. El código del servidor depende de usted (si es suyo), pero la mayoría de los proveedores de datos de Ajax le permiten especificar el método de devolución de llamada en parámetros como lo hicimos nosotros. en Ruby on Rails que acabo de hacer

render :json=>MyModel.all(:limit=>10), :callback => params[:callback],:content_type => "application/json" 

y eso es todo, ahora se puede extraer datos de otro dominio de sus aplicaciones (widgets, mapas, etc.), sólo en formato JSON, no se olvide.

espero que haya sido útil, gracias por su paciencia :-), paz y perdón por el formato de código, que no funciona bien

16

Puede utilizar YQL hacer la solicitud sin necesidad de alojar su propio Proxy . He hecho una simple función para que sea más fácil de ejecutar comandos:

function RunYQL(command, callback){ 
    callback_name = "__YQL_callback_"+(new Date()).getTime(); 
    window[callback_name] = callback; 
    a = document.createElement('script'); 
    a.src = "http://query.yahooapis.com/v1/public/yql?q=" 
      +escape(command)+"&format=json&callback="+callback_name; 
    a.type = "text/javascript"; 
    document.getElementsByTagName("head")[0].appendChild(a); 
} 

Si tiene jQuery, es posible utilizar $ .getJSON lugar.

Una muestra puede ser esta:

RunYQL('select * from html where url="http://www.google.com/"', 
     function(data){/* actions */} 
); 
1

Aquí es una manera fácil de lo que puede hacerlo, sin tener que usar algo de fantasía, o incluso JSON.

Primero, cree una secuencia de comandos del lado del servidor para manejar sus solicitudes. Algo así como http://www.example.com/path/handler.php

Va a llamarlo con los parámetros, así:? .../handler.php param1 = 12345 & param2 = 67890

Dentro de ella, después de procesar los datos recibido, salida:

document.serverResponse('..all the data, in any format that suits you..'); 
// Any code could be used instead, because you dont have to encode this data 
// All your output will simply be executed as normal javascript 

Ahora, en el script del lado del cliente, utilice la siguiente:

document.serverResponse = function(param){ console.log(param) } 

var script = document.createElement('script'); 
script.src='http://www.example.com/path/handler.php?param1=12345&param2=67890'; 
document.head.appendChild(script); 

El único límite de este enfoque es la longitud máxima de parámetros que puede enviar al servidor. Pero, siempre puedes enviar múltiples solicitudes.

2

Si está utilizando un script php para obtener la respuesta desde el servidor remoto, agregue esta línea al comienzo:

header("Access-Control-Allow-Origin: *"); 
Cuestiones relacionadas