Правильный способ рендеринга JavaScript на стороне сервера - PullRequest
0 голосов
/ 12 июня 2018

У меня есть многостраничный веб-сайт, который использует React в качестве прославленного инструментария виджетов (разные пакеты на разных страницах).Однако некоторое состояние виджета сохраняется в сеансе входа в систему. Когда пользователь снова открывает страницу, компоненты должны перезагрузить свое начальное состояние.В настоящее время я делаю это следующим образом:

  1. Обслуживание страницы вместе с ее JS-пакетом
  2. 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 не будет простого способа рендеринга, так как передача строки вида &lt;script&gt; отразит это буквально, согласно этой странице..

Единственное решение, которое я вижу, чтобы заставить это работать таким образом, - это избегать оскорбительных символов при выходе из Юникода.

Примечание: я знаю, что это весьма неортодоксально, ноЯ хочу увидеть что-нибудь получше, если не что иное, как мысленное упражнение.

1 Ответ

0 голосов
/ 12 июня 2018

При выводе содержимого массива filters в элемент script выполните две вещи:

  1. Убедитесь, что они правильно сформированы строковыми литералами.Простой способ сделать это - передать строку фильтра в JSON.stringify.

  2. Убедитесь, что последовательность </script> никогда не встречается буквально, что довольно легко сделать с помощью регулярного выражения.(Это необходимо только потому, что вы выводите эти строки в теле тега 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...