Tho*_*mas 6 html javascript json nunjucks
我们有一个服务器端呈现的HTML页面,其中包含一个外部JavaScript文件。要触发该文件中的代码,我们要调用一个函数并向其传递一些动态数据(以JSON的形式):
<script src="/static/foo/bar.js"></script>
<script>
foo.bar.init({biz: 42, qux: "quux"});
</script>
Run Code Online (Sandbox Code Playgroud)
我们从Nunjucks模板渲染它,并将JSON对象作为值传递data给上下文。它可以包含任意数据,包括用户提供的内容。
这是安全的,但是不起作用,因为<>&已经被逃脱了(由于Nunjucks自动转义):
foo.bar.init({{ data | dump }});
Run Code Online (Sandbox Code Playgroud)
这是可行的,但并不安全,因为JSON中的字符串可能包含以下文本</script>:
foo.bar.init({{ data | dump | safe }});
Run Code Online (Sandbox Code Playgroud)
如何说服Nunjucks渲染此JSON,以便可以安全正确地对其进行解释?听起来应该是一个已解决的问题,但是我在任何地方都找不到预制的解决方案。
现在这样做:
/**
* Returns a JSON stringified version of the value, safe for inclusion in an
* inline <script> tag. The optional argument 'spaces' can be used for
* pretty-printing.
*
* Output is NOT safe for inclusion in HTML! If that's what you need, use the
* built-in 'dump' filter instead.
*/
env.addFilter('json', function (value, spaces) {
if (value instanceof nunjucks.runtime.SafeString) {
value = value.toString()
}
const jsonString = JSON.stringify(value, null, spaces).replace(/</g, '\\u003c')
return nunjucks.runtime.markSafe(jsonString)
})
Run Code Online (Sandbox Code Playgroud)
用法:
<script src="/static/foo/bar.js"></script>
<script>
foo.bar.init({{ data | json }});
</script>
Run Code Online (Sandbox Code Playgroud)
更好的解决方案仍然受欢迎。