2008-09-16 16 views
34

Estoy trabajando en una página web en la que estoy haciendo una llamada AJAX que devuelve un trozo de HTML como:¿Cómo se ejecuta un bloque de JavaScript cargado dinámicamente?

<div> 
    <!-- some html --> 
    <script type="text/javascript"> 
    /** some javascript */ 
    </script> 
</div> 

estoy insertando todo el asunto en el DOM, pero el JavaScript no está siendo ejecutado. ¿Hay alguna forma de ejecutarlo?

Algunos detalles: No puedo controlar lo que hay en el bloque de script (así que no puedo cambiarlo a una función que podría llamarse), solo necesito que se ejecute todo el bloque. No puedo llamar a eval en la respuesta porque el JavaScript está dentro de un bloque más grande de HTML. Podría hacer algún tipo de expresión regular para separar el JavaScript y luego llamar a eval, pero eso es bastante asqueroso. Alguien sabe una mejor manera?

Respuesta

14

La secuencia de comandos añadida al establecer la propiedad innerHTML de un elemento no se ejecuta. Intenta crear un nuevo div, configurando su innerHTML, y luego agrega este nuevo div al DOM. Por ejemplo:

 
<html> 
<head> 
<script type='text/javascript'> 
function addScript() 
{ 
    var str = "<script>alert('i am here');<\/script>"; 
    var newdiv = document.createElement('div'); 
    newdiv.innerHTML = str; 
    document.getElementById('target').appendChild(newdiv); 
} 
</script> 
</head> 
<body> 
<input type="button" value="add script" onclick="addScript()"/> 
<div>hello world</div> 
<div id="target"></div> 
</body> 
</html> 
+1

Este script no funciona en IE 7. IE 7 parece tener un error con la función appendChild. – Eddie

+2

No funciona, usando google cromo 26. – prashn64

+3

no funciona en ningún navegador moderno (firefox, cromo, safari) – Roy

14

No tiene que usar expresiones regulares si está utilizando la respuesta para completar un div o algo así. Puede usar getElementsByTagName.

div.innerHTML = response; 
var scripts = div.getElementsByTagName('script'); 
for (var ix = 0; ix < scripts.length; ix++) { 
    eval(scripts[ix].text); 
} 
+7

esto parece altamente vulnerables a los ataques de inyección y otros vectores ... –

1

El mejor método probablemente sería identificar y evaluar los contenidos del bloque de scripts directamente a través del DOM.

Sin embargo, sería cuidadoso ... si está implementando esto para superar la limitación de una llamada fuera del sitio, está abriendo un agujero de seguridad.

Cualquier cosa que implemente podría explotarse para XSS.

+0

corrígeme si me equivoco, pero la Entiendo las vulnerabilidades de XSS en este tipo de situaciones, es solo un problema si te preocupa que alguien pueda obtener acceso a la cuenta en línea de otra persona, y así pueda robar información sensible, pero si no es posible para los usuarios inicie sesión en el sitio, entonces esto no es una preocupación. –

2

Una alternativa es no solo volcar el retorno de la llamada Ajax al DOM usando InnerHTML.

Puede insertar cada nodo dinámicamente y luego se ejecutará la secuencia de comandos.

De lo contrario, el navegador simplemente supone que está insertando un nodo de texto e ignora los scripts.

El uso de Eval es bastante malo, porque requiere que se active otra instancia de la VM de Javascript y JIT la cadena pasada.

+12

Sería muy bueno si explicas cómo insertar cada nodo dinámicamente. – mandza

0

Puede utilizar una de las bibliotecas populares de Ajax que lo hacen de forma nativa. Me gusta Prototype. Solo puede agregar evalScripts: verdadero como parte de su llamada Ajax y ocurre de manera automágica.

-1

A continuación se muestra un enfoque diferente de bits que utiliza el hecho de que si la etiqueta contiene type = "text/xml" JavaScript en el interior no se ejecutará:

function preventJS(html) { 
    return html.replace(/<script(?=(\s|>))/i, '<script type="text/xml" '); 
} 

Puede leer más aquí - JavaScript: How to prevent execution of JavaScript within a html being added to the DOM. Si le funciona, deje aquí un comentario con información sobre el navegador y la versión que ha utilizado.

5

Si bien la respuesta aceptada de @Ed. no funciona en las versiones actuales de los navegadores Firefox, Google Chrome o Safari. Pude adaptar su ejemplo para invocar scripts añadidos dinámicamente.

Los cambios necesarios son solo en la forma en que los scripts se agregan al DOM.En lugar de agregarlo como innerHTML, el truco fue crear un nuevo elemento de script y agregar el contenido del script real como innerHTML al elemento creado y luego agregar el elemento del script al objetivo real.

<html> 
<head> 
<script type='text/javascript'> 
function addScript() 
{ 
    var newdiv = document.createElement('div'); 

    var p = document.createElement('p'); 
    p.innerHTML = "Dynamically added text"; 
    newdiv.appendChild(p); 

    var script = document.createElement('script'); 
    script.innerHTML = "alert('i am here');"; 
    newdiv.appendChild(script); 

    document.getElementById('target').appendChild(newdiv); 
} 
</script> 
</head> 
<body> 
<input type="button" value="add script" onclick="addScript()"/> 
<div>hello world</div> 
<div id="target"></div> 
</body> 
</html> 

Esto funciona para mí en Firefox 42, Google Chrome 48 y Safari 9.0.3

Cuestiones relacionadas