2012-04-09 31 views
20

¿Cómo solucionaría el problema de dominio cruzado al analizar XML desde un servidor/dominio diferente? ¿Podría alguien darme un ejemplo? El ejemplo no tiene que estar restringido solo a jQuery, ya que JavaScript también será suficiente.Cómo analizar XML entre dominios en jQuery?

+0

qué quiere decir con dominio cruzado –

+1

Solo la ejecución de dominios cruzados permitida desde JavaScript es JSONP. – AlienWebguy

+0

"Las solicitudes de script y JSONP no están sujetas a las mismas restricciones de política de origen". –

Respuesta

66

Para comprender completamente por qué pure XML de dominios cruzados no funcionará, es útil observar primero cómo se facilita el dominio cruzado de JSON.

En primer lugar, vamos a ver lo que sucede cuando se hace una petición AJAX de jQuery:

$.ajax({ 
    url: '/user.php?userId=123', 
    success: function(data) { 
     alert(data); // alerts the response 
    }); 

En el ejemplo anterior, la petición AJAX se hace en relación con el dominio. Sabemos que si intentamos agregar un dominio diferente antes de la ruta, la solicitud fallará con una excepción de seguridad.

Sin embargo, eso no quiere decir que el navegador no pueda realizar solicitudes a otro dominio. Aquí está un ejemplo que puede ser familiar para usted:

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script> 

Basado en nuestro conocimiento de cómo importar JavaScript en la página, vemos que es posible cargar un recurso que existe en otro dominio!

JSONP es un concepto que explota este conocimiento. JSONP significa "JSON con relleno", y su éxito depende del hecho de que los Objetos JavaScript se puedan expresar usando una notación de cadena, y el hecho de que las etiquetas JavaScript pueden cargar y ejecutar contenido desde dominios externos.

Bajo el capó, JSONP de jQuery se ve algo como esto a pesar de que puede no ser exacta:

// programmatically load a script tag on the page using the given url 
function loadRemoteData(url) { 
    var script = document.createElement("script"); 
    script.setAttribute("type","text/javascript"); 
    script.setAttribute("src", url); 
    document.getElementsByTagName("head")[0].appendChild(script); 
} 

Además, en la página de algún lugar, definimos un controlador de devolución de llamada:

function processData(jsonResult) { 
    alert(JSON.stringify(jsonResult)); //alert the JSON as a string 
} 

Aquí, Hacemos la solicitud:

// make a request for the data using the script tag remoting approach. 
loadRemoteData("http://example.com/users.php?userId=123&callback=processData"); 

Para que esto funcione correctamente, nuestro script PHP debe ambos devuelven los datos en formato JSON y también deben agregar "relleno" alrededor de la cadena en forma de un nombre de función de JavaScript que podemos pasar como un parámetro (es decir, "Callback")

Por lo tanto, la respuesta del servidor puede ser algo como esto, si tuviéramos que mirar en el Firebug o Chrome pestaña NET:

processData({ "userId" : "123" , "name" : "James" , "email" : "[email protected]" }); 

Porque sabemos contenido de JavaScript se ejecuta como tan pronto como se descargue, nuestra función processData que definimos anteriormente se llama inmediatamente y se pasa nuestra cadena JSON como parámetro. Luego se alerta, usando JSON.stringify para convertir el objeto nuevamente en una cadena.

Ya que es un objeto, también pude acceder a sus propiedades, así:

function processData(jsonResult) { 
    alert(JSON.stringify(jsonResult)); //alert the JSON as a string 

    // alert the name and email 
    alert("User name is " + jsonResult.name + " and email is " + jsonResult.email); 
} 

Por último, vamos a pasar a la pregunta principal: Puede jsonp usarse para obtener XML, o podemos analizar cruz XML -¿dominio? La respuesta, como otros han señalado, es un rotundo NO, pero vamos a ver qué utilizando un ejemplo:

processData(<?xml version="1.0"><user><userid>12345</userid><name>James</name><email>[email protected]</email></user>); 

Ahora, lo que ocurrirá si XML sin procesar se pasa a la función? Se romperá, ya que JavaScript no tiene forma de convertir XML en JSON.

Sin embargo, supongamos que ponemos el XML entre comillas:

processData("<?xml version="1.0"><user><userid>12345</userid><name>James</name><email>[email protected]</email></user>"); 

Ahora, en este ejemplo, la variable JsonResult realmente tiene una cadena, que podemos trabajar con ellos. Utilizando algunas utilidades de análisis XML de JavaScript, podríamos cargar esa cadena en el Analizador DOM de XML y ¡hacer cosas con eso!

Sin embargo, no es XML puro, sigue siendo una respuesta de JavaScript bajo el capó. El tipo de respuesta del servidor PHP sigue siendo texto/javascript, y todavía estamos usando una etiqueta de script para cargar lo que realmente es simplemente JavaScript.

En resumen, podría trabajar con "XMLP" o XML con relleno (¡ya lo inventé, no es real!), Pero si va a pasar por todo el trabajo de modificar su respuesta a devuelve un envoltorio de devolución de llamada a la función, también puedes convertir tu salida a JSON y dejar que el navegador maneje las conversiones de forma automática y nativa y evitarte el problema de tener que usar un analizador XML.

Pero si por alguna razón es más fácil mantener sus datos en formato XML, podría modificar la respuesta y darle un contenedor de JavaScript.

Casos en los que podría ver que esto puede ser útil podrían serlo si tiene datos XML de una aplicación heredada almacenada en una base de datos, y los devuelve al lado del cliente mediante conversaciones remotas de secuencias de comandos o llamadas JSONP.

+8

que es muy útil, +1. Te mereces kudos – defau1t

4

Encontré una muy buena solución para recuperar xml de la solicitud ajax de dominios cruzados.

Desde jQuery 1.5 puede usar dataType "jsonp xml" (http://api.jquery.com/jQuery.ajax/)!

así que utilicé la siguiente: lado

$.ajax({ 
      type: "GET", 
      url: "http://yoururl", 
      dataType: "jsonp xml", 
      success: function(xmlResponse) { // process data } 
     }); 

servidor para mis servicios web i utilizado para encapsular el resultado cadena XML dentro de la devolución de llamada creado por jQuery:

private static Stream GetXmlPStream(string result, string callback) 
     { 
      if (result == null) 
       result = string.Empty; 

      result = EncodeJsString(result); 

      if (!String.IsNullOrEmpty(callback)) 
       result = callback + "(" + result + ");"; 

      byte[] resultBytes = Encoding.UTF8.GetBytes(result); 

      if (WebOperationContext.Current != null) 
       WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml"; 
      return new MemoryStream(resultBytes); 
     } 

y el método mágico (he encontrado en otro subproceso de Stack) que necesitará desinfectar su cadena xml (para que javascript pueda analizarlo):

private static string EncodeJsString(string s) 
     { 
      StringBuilder sb = new StringBuilder(); 
      sb.Append("\""); 
      foreach (char c in s) 
      { 
       switch (c) 
       { 
        case '\"': 
         sb.Append("\\\""); 
         break; 
        case '\\': 
         sb.Append("\\\\"); 
         break; 
        case '\b': 
         sb.Append("\\b"); 
         break; 
        case '\f': 
         sb.Append("\\f"); 
         break; 
        case '\n': 
         sb.Append("\\n"); 
         break; 
        case '\r': 
         sb.Append("\\r"); 
         break; 
        case '\t': 
         sb.Append("\\t"); 
         break; 
        default: 
         int i = (int)c; 
         if (i < 32 || i > 127) 
         { 
          sb.AppendFormat("\\u{0:X04}", i); 
         } 
         else 
         { 
          sb.Append(c); 
         } 
         break; 
       } 
      } 
      sb.Append("\""); 

      return sb.ToString(); 
     } 

Espero que esto ayude!

+9

Recibí un error 'Sincapt SyntaxError: Inexpected token <' cuando probé esto, por ejemplo: '$ .get ('http://www.webservicex.net/geoipservice.asmx/GetGeoIPContext', función (datos) {console.log (data);}, 'jsonp xml'); ' – 10basetom

+2

Esto es útil solo cuando tiene acceso al código del servidor. –