2011-11-22 6 views
2

J'ai un hachage Ruby qui contient une chaîne générée par l'utilisateur. Je dois passer ce hash à JavaScript pour qu'il puisse être traité. J'ai essayé d'utiliser JSON, qui fonctionne la plupart du temps, mais casse quand le hachage contient le texte </script>. Voici le code le plus simple qui casse dans Chrome et FF8:Passez l'objet Ruby en JavaScript en toute sécurité

<% 
obj = { 
    :foo => '</script>' 
} 
%> 
<script type="text/javascript"> 
var obj = <%= obj.to_json %>; // Results in JS syntax error 
</script> 

Il en résulte le code HTML suivant:

<script type="text/javascript"> 
var obj = {"foo":"</script>"}; 
</script> 

J'ai aussi essayé envelopper le JSON entre guillemets (simple et double) il peut être analysé par jQuery.parseJSON(), mais il en résulte la même erreur de syntaxe:

<% 
obj = { 
    :foo => '</script>' 
} 
%> 
<script type="text/javascript"> 
var json = '<%= obj.to_json %>'; // Again results in JS syntax error 
</script> 

il semble que l'erreur de syntaxe est un résultat du navigateur en essayant d'interpréter le </script> texte à la fin du bloc de script. Ma solution actuelle est d'échapper à la chaîne JSON comme HTML, échapper antislashs reste, écrire à JS comme une chaîne, unescape le code HTML, puis analyser enfin le JSON:

<% 
obj = { 
    :foo => '</script>' 
} 
json = obj.to_json 
escaped_json = CGI.escapeHTML(json) 
slashed_escaped_json = escaped_json..gsub(/['"\\\x0]/,'\\\\\0') 
%> 
<script type="text/javascript"> 
var json = "<%= slashed_escaped_json %>"; 
json = $('<div/>').html(json).text(); // unescape HTML 
var obj = jQuery.parseJSON(json); // parse JSON safely 
console.log(obj); 
</script> 

Il fonctionne, mais il est laid. Y a-t-il un meilleur moyen? Je ne veux pas supprimer </script> car j'échappe au contenu des entités HTML avant de le rendre sur la page.

Répondre

0

Il s'avère que c'est un bug dans la gemme "json" pour Ruby. J'ai localisé la source sur GitHub et trouvé cette demande de traction assis dans la file d'attente:

https://github.com/flori/json/pull/51

La solution est d'échapper à la barre oblique, ce qui JSON comme ceci:

{"foo":"<\/script>"} 

Merci pour toute votre aide et j'espère que cette solution aidera quelqu'un d'autre!

0

Si vous pensez qu'il y a un problème avec le navigateur, veuillez montrer le balisage qui en résulte, pas le rubis.

J'ai résolu des problèmes similaires dans le passé en codant en base64 le json côté serveur. Puis le décoder et json.parsing sur le côté client.

+0

J'ai mis à jour la question par commentaire. J'ai considéré Base64, mais plutôt utilisé l'encodage html dans ma solution laide. Il obtient le même résultat, mais me semble encore mal :( –

0

est-il une raison que vous non seulement faire une autre rappel à votre serveur pour récupérer le JSON dans une autre demande, comme ceci:

var foo; 
jQuery.get('/your_controller/' + resource_id + '/controller_action.json', null, function(data) { 
    try { 
    foo = data 
    } catch (e) {   
     console.log("Error get data: " + e.message); 
    } 
}); 

Je ne sais pas vraiment ce que votre demande est, mais C'est une option qui fonctionne.

+1

C'est une très bonne idée, mais pourquoi faire deux requêtes quand cela peut être fait en un? –

Questions connexes