在ExpressJS中将variables传递给JavaScript
我完全失去了这一点; 我正在使用NodeJS来获取JSON,我需要将该variables传递给我的页面,并使JavaScript使用数据。
app.get('/test', function(req, res) { res.render('testPage', { myVar: 'My Data' });
这是我的Express代码(testing非常简单); 现在使用EJS我想收集这些我知道在页面上呈现的数据很简单
<%= myVar %>
但我需要能够收集这些数据在JavaScript(如果可能在.js文件中),但现在只是要显示在一个警报框中的variables我已经尝试
在Jade中它就像alert('!{myVar}')
或!{JSON.stringify(myVar)}
。 我可以在EJS中做类似的事吗? 我不需要任何像<input type=hidden>
的字段,并在javascript中使用字段的值。 如果有人可以帮助非常感激
你可以使用这个(客户端):
<script> var myVar = <%- JSON.stringify(myVar) %>; </script>
您也可以让EJS呈现一个.js
文件:
app.get('/test.js', function(req, res) { res.set('Content-Type', 'application/javascript'); res.render('testPage', { myVar : ... }); });
但是,模板文件( testPage
)仍然需要具有.html
扩展名,否则EJS将无法find它(除非您以其他方式告诉Express)。
正如@ksloan在评论中指出的:你必须小心myVar
包含的内容。 如果它包含用户生成的内容,则可能会使您的站点打开脚本注入攻击。
防止这种情况发生的可能的解决scheme:
<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>
尝试这个:
<script type="text/javascript"> window.addEventListener('load', function(){ alert('<%= myVar %>'); }); </script>
这里的主要困难是避免XV风险,如果myVar包含引号,或者</script>
。 为了避免这个问题,我build议在JSON.stringify之后使用Base64编码。 这样可以避免与引号或HTML标签相关的所有风险,因为Base64只包含“安全”字符来放入带引号的string。
我提出的解决scheme是:
EJS文件:
<script> var myVar = <%- passValue(myVar) %> </script>
这将渲染成类似的东西(例如这里myVar = null):
<script> var myVar = JSON.parse(Base64.decode("bnVsbA==")) </script>
服务器端NodeJS:
function passValue(value) { return 'JSON.parse(Base64.decode("' + new Buffer(JSON.stringify(value)).toString('base64') + '"))' }
客户端JS(这是一个与Unicode一起工作的Base64解码实现,如果您愿意,可以使用另一个,但是如果它支持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}}
如果你有像数组这样更复杂的对象,你可以这样做:
<% if (myVar) { %> <script> myVar = JSON.parse('<%- JSON.stringify(myVar) %>'); </script> <% } %>
否则,您以前看到的解决scheme将无法正常工作
根据这里的文档:
转到最新版本 ,下载./ejs.js或./ejs.min.js。
在你的页面上包含这些内容之一,和ejs.render(str)
。
在接受的解决scheme中,如果myVar具有带有未转义双引号的值的属性,则JSON.parse将失败。 那么更好的遍历对象并且转义每个string属性。
这是一个涵盖我的情况的function:
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; };
比在ejs你只需要:
<% 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); %>
现在你可以安全地使用非转义的语法
window.product = <%-JSON.stringify(encodedProduct)%>;