服务器端呈现JavaScript的正确方法

时间:2018-06-12 15:45:15

标签: javascript html reactjs webserver

我有一个多页面网站,它使用React作为一个美化的小部件工具包(不同页面上的不同包)。但是,某些窗口小部件状态在登录会话内持续存在当用户重新打开页面时,组件应重新加载其初始状态。我目前这样做:

  1. 提供页面及其JS包
  2. AJAX在挂载所有内容时从服务器获取状态
  3. 这看起来很浪费,因为后端已经知道页面是什么,以及小部件的初始状态。所以我考虑渲染初始状态,作为服务页面内的普通对象,让对象在安装时获取它。

    我最初的尝试将初始状态表示为:

    [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中渲染它并不容易,因为传递&lt;script&gt;形式的字符串会按字面意思呈现,{{3 }}

    我认为以这种方式工作的唯一解决方案是在unicode转义时逃避违规字符。

    注意:我知道这是非常不正统的,但我希望看到任何更好的选择,如果不是思考练习。

1 个答案:

答案 0 :(得分:1)

filters数组的内容输出到script元素时,请执行以下两项操作:

  1. 确保它们是正确形成的字符串文字。一种简单的方法是将过滤字符串传递给JSON.stringify

  2. 确保序列</script>从不按字面意思发生,这很容易用正则表达式完成。 (这只是必要的,因为您在script标记的正文中输出这些字符串;如果它们是通过.js加载的外部src文件中输入的话,那就不会无所谓。)

  3. 例如,对于每个过滤字符串

    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;
    }