我有一个多页面网站,它使用 React 作为美化的小部件工具包(不同页面上的不同包)。但是,某些小部件状态会在登录 session 中持续存在。当用户重新打开页面时,组件应重新加载其初始状态。我目前通过以下方式执行此操作:
- 提供页面及其 JS 包
- AJAX 在安装所有内容时从服务器获取状态
这看起来很浪费,因为后端已经知道页面是什么,也知道小部件的初始状态。所以我考虑将初始状态呈现为服务页面内的普通对象,并让该对象在挂载时获取它。
我最初的尝试将初始状态呈现为:
[some other HTML ... ]
<script>
var WIDGET_INITIAL_STATE = {
startDate: '...',
filters: ['filter1', 'filter2', ... ]
}
</script>
然后在组件设置中使用这个全局变量。当然,这是不安全的,因为 filters
由文本输入控制,因此如果输入 </script> [ arbitrary HTML ] <script>
,上面会变成:
<script>
var WIDGET_INITIAL_STATE = {
startDate: '...',
filters['<script>
[arbitrary HTML]
</script>', 'filter2']
}
</script>
这是灾难性的糟糕。
但是,如果我进行尽职调查并在服务器端对其进行清理,则没有简单的方法可以在 React 中呈现它,因为传递一个形式为 <script>
的字符串。会根据 this page 逐字呈现.
我认为以这种方式工作的唯一解决方案是在 unicode 转义时转义违规字符。
注意:我知道这是非常不正统的,但我希望看到任何更好的做法,如果没有别的,那就是思考练习。
最佳答案
当输出你的 filters
的内容时数组到 script
元素,做两件事:
确保它们是格式正确的字符串文字。一个简单的方法是将过滤器字符串传递给
JSON.stringify
.确保序列
</script>
never occurs literally,这很容易用正则表达式完成。 (这只是必要的,因为您在script
标记的正文中输出这些字符串;如果它们进入通过.js
加载的外部src
文件,这无关紧要。)
例如,对于每个过滤器字符串
stringToOutputToFiltersArray = JSON.stringify(filterString.replace(/<\s*\/\s*script\s*>/gm, "<\\/script>"))
// "server side" code
var filters = [
'filter1',
'<script> [arbitrary HTML] </sc' + 'ript>',
'filter3'
];
var inlineScript =
"<script>\n" +
"var WIDGET_INITIAL_STATE = {\n" +
" startDate: '...',\n" +
" filters: [" + filters.map(filter =>
JSON.stringify(filter.replace(/<\s*\/\s*script\s*>/gm, "<\\/script>"))
) + "]\n" +
"};\n" +
"</sc" + "ript>";
document.write(inlineScript);
console.log("filters:", filters);
console.log("inlineScript:", inlineScript);
console.log("WIDGET_INITIAL_STATE.filters[1] = ", WIDGET_INITIAL_STATE.filters[1]);
.as-console-wrapper {
max-height: 100% !important;
}
关于javascript - 服务器端渲染 JavaScript 的正确方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50821109/