web-dev-qa-db-fra.com

Passer des variables à JavaScript dans ExpressJS

Je suis complètement perdu à ce sujet; J'utilise NodeJS pour récupérer un fichier JSON et je dois transmettre la variable à ma page et laisser JavaScript utiliser les données.

app.get('/test', function(req, res) {
    res.render('testPage', {
        myVar: 'My Data'
    });

C’est mon code Express (très simple à des fins de test); maintenant en utilisant EJS je veux rassembler ces données que je sais rendre sur la page est tout simplement

<%= myVar %>

Mais je dois pouvoir rassembler ces données en JavaScript (si possible dans un fichier .js), mais pour l'instant, il suffit d'essayer d'afficher la variable dans une zone d'alerte.

En Jade, c'est comme alert('!{myVar}') ou !{JSON.stringify(myVar)}. Puis-je faire quelque chose de similaire dans EJS. Je n'ai besoin d'aucun champ comme <input type=hidden> et je prends la valeur du champ en javascript. Si quelqu'un peut aider est très apprécié

35
Jetson John

Vous pouvez utiliser ceci (côté client):

<script>
  var myVar = <%- JSON.stringify(myVar) %>;
</script>

Vous pouvez également demander à EJS de générer un fichier .js:

app.get('/test.js', function(req, res) {
  res.set('Content-Type', 'application/javascript');
  res.render('testPage', { myVar : ... });
});

Cependant, le fichier de modèle (testPage) doit toujours porter l'extension .html, sinon EJS ne le trouvera pas (sauf indication contraire d'Express).

Comme @ksloan le fait remarquer dans les commentaires: vous devez faire attention à ce que contient myVar. S'il contient du contenu généré par l'utilisateur, votre site peut rester ouvert aux attaques par injection de script.

Une solution possible pour éviter cela:

<script>
  function htmlDecode(input){
    var e = document.createElement('div');
    e.innerHTML = input;
    return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
  }
  var myVar = JSON.parse(htmlDecode("<%= JSON.stringify(myVar) %>"));
</script>
63
robertklep

La principale difficulté consiste ici à éviter les risques XSS si myVar contient des guillemets, ou </script> par exemple. Pour éviter ce problème, je propose d'utiliser Base64 encoding après JSON.stringify. Cela éviterait tous les risques liés aux guillemets ou aux balises HTML puisque Base64 ne contient que des caractères "sûrs" pour insérer une chaîne entre guillemets.

La solution que je propose:

Fichier EJS:

<script>
  var myVar = <%- passValue(myVar) %>
</script>

qui rendra quelque chose comme (par exemple ici myVar = null):

<script>
  var myVar = JSON.parse(Base64.decode("bnVsbA=="))
</script>

NodeJS côté serveur:

function passValue(value) {
  return 'JSON.parse(Base64.decode("' + new Buffer(JSON.stringify(value)).toString('base64') + '"))'
}

JS côté client (c'est une implémentation du décodage Base64 qui fonctionne avec Unicode, vous pouvez en utiliser une autre si vous préférez, mais soyez prudent si elle prend en charge Unicode):

var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(e){var t="";var n,r,i,s,o,u,a;var f=0;e=Base64._utf8_encode(e);while(f<e.length){n=e.charCodeAt(f++);r=e.charCodeAt(f++);i=e.charCodeAt(f++);s=n>>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+this._keyStr.charAt(s)+this._keyStr.charAt(o)+this._keyStr.charAt(u)+this._keyStr.charAt(a)}return t},decode:function(e){var t="";var n,r,i;var s,o,u,a;var f=0;e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");while(f<e.length){s=this._keyStr.indexOf(e.charAt(f++));o=this._keyStr.indexOf(e.charAt(f++));u=this._keyStr.indexOf(e.charAt(f++));a=this._keyStr.indexOf(e.charAt(f++));n=s<<2|o>>4;r=(o&15)<<4|u>>2;i=(u&3)<<6|a;t=t+String.fromCharCode(n);if(u!=64){t=t+String.fromCharCode(r)}if(a!=64){t=t+String.fromCharCode(i)}}t=Base64._utf8_decode(t);return t},_utf8_encode:function(e){e=e.replace(/\r\n/g,"\n");var t="";for(var n=0;n<e.length;n++){var r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r)}else if(r>127&&r<2048){t+=String.fromCharCode(r>>6|192);t+=String.fromCharCode(r&63|128)}else{t+=String.fromCharCode(r>>12|224);t+=String.fromCharCode(r>>6&63|128);t+=String.fromCharCode(r&63|128)}}return t},_utf8_decode:function(e){var t="";var n=0;var r=c1=c2=0;while(n<e.length){r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r);n++}else if(r>191&&r<224){c2=e.charCodeAt(n+1);t+=String.fromCharCode((r&31)<<6|c2&63);n+=2}else{c2=e.charCodeAt(n+1);c3=e.charCodeAt(n+2);t+=String.fromCharCode((r&15)<<12|(c2&63)<<6|c3&63);n+=3}}return t}}
6

Essaye ça:

<script type="text/javascript">
     window.addEventListener('load', function(){
         alert('<%= myVar %>');
     });
</script>
3
karaxuna

si vous avez des objets plus complexes comme un tableau, vous pouvez le faire:

<% if (myVar) { %>
   <script>
      myVar = JSON.parse('<%- JSON.stringify(myVar) %>');
   </script>
<% } %>

sinon, les solutions précédentes que vous avez vues ne fonctionneront pas

2
Benjamin Fuentes

Voici comment je l'ai fait fonctionner, Dans le noeud js passe le json comme ceci

let j =[];
//sample json
j.Push({data:"hi});

res.render('index',{json:j});

maintenant en fonction js

var json = JSON.parse('<%- JSON.stringify(json) %>');

Cela a bien fonctionné pour moi

1
Jerin A Mathews

Dans la solution acceptée, JSON.parse échouera si myVar a une propriété avec une valeur avec guillemets doubles non échappés. Donc, mieux traverseObj et échappe chaque propriété de chaîne.

Voici une fonction qui couvre mon cas:

function traverseObj (obj, callback)
{
    var result = {};
    if ( !isArray(obj) && !isObject(obj) ) {
         return callback(obj);
    }

    for ( var key in obj ) {
        if ( obj.hasOwnProperty(key) ) {
            var value = obj[key];
            if (isMongoId(value)){
                var newValue = callback(value.toString());
                result[key] = newValue;
            }
            else if (isArray ( value) ) {
                var newArr = [];
                for ( var i=0; i < value.length; i++ ) {
                    var arrVal = traverseObj(value[i], callback);
                    newArr.Push(arrVal);
                }
                result[key] = newArr;
            }
            else if ( isObject(value) ) {
                result[key] = traverseObj(value, callback);
            }
            else {
                var newValue = callback(value);
                result[key] = newValue;
            }
        }
    }
    return result;
};

Dans ejs, vous devez simplement: 

<%
    var encodeValue = function(val) {
        if ( typeof val === 'string' ) {
            return sanitizeXSS(val); //use some library (example npm install xss)
        }
        return val;
    }

    var encodedProduct = ejs_utils.traverseObj(product, encodeValue);
%>

et maintenant vous pouvez transporter en toute sécurité avec une syntaxe non échappée

window.product = <%-JSON.stringify(encodedProduct)%>;
0
user732456

Selon la documentation ici :

Allez à la Dernière version , téléchargez ./ejs.js ou ./ejs.min.js.

Incluez-en un sur votre page et ejs.render(str).

0
spitz