【问题标题】:React dangerouslySetInnerHTML breaks JSON config with & characterReact dangerouslySetInnerHTML 用 & 字符破坏 JSON 配置
【发布时间】:2020-08-18 17:24:40
【问题描述】:

我正在尝试将 amp-analytics 脚本放入从 Next.js 生成的 amp 页面中,但由于 & 字符,SetInnerHTML 很危险地破坏了 JSON 配置。

代码如下:

<amp-analytics id='analytics1' type='googleanalytics'>
  <script type='application/json' dangerouslySetInnerHTML={{ __html: `
    {
      "vars": {
        "account": "XX-XXXXXXXX-X"
      },
      "requests": {
         "experiment": "\${pageview}&xid=\${xid}&xvar=\${xvar}"
      }
    }
  ` }} />
</amp-analytics>

结果如下:

如您所见,& 字符已转换为 \u0026,现在 amp-analytics 标记不起作用。

我也试过这个:

<amp-analytics id='analytics1' type='googleanalytics'>
  <script type='application/json' dangerouslySetInnerHTML={{ __html: `
    {
      "vars": {
        "account": "XX-XXXXXXXX-X"
      },
      "requests": {
         "experiment": "${JSON.stringify('${pageview}&xid=${xid}&xvar=${xvar}')}"
      }
    }
  ` }} />
</amp-analytics>

但得到的 JSON 无效(带有右 & 符号)

关于如何解决这个问题的任何想法?

事实证明,这是因为 Next.js 中的 AMP Optimizer — github.com/ampproject/amp-toolbox/pull/649 而现在我必须为这种情况找到解决方案

【问题讨论】:

  • 在第二次尝试中删除 ${JSON.stringify(...)} 周围的引号。
  • @Al.G.,在这种情况下,我得到与第一次尝试相同的结果。我还尝试在不同的沙箱中重现它——react、react with amp、next.js 沙箱——它在任何地方都能正常工作,它返回有效且正确的 JSON。不知道为什么在我的项目中它不能正常工作
  • 看起来是 next.js 放大器优化器问题,因为它在非放大器页面上运行良好...
  • 好的,那我不知道是什么原因造成的。回滚了我的编辑。

标签: next.js google-optimize amp-analytics


【解决方案1】:

您不需要使用dangerouslySetInnerHTML,因为您要做的只是设置文本内容。仅当您需要将 HTML 解析为 DOM 节点时才需要dangerouslySetInnerHTML

你可以这样设置文本内容:

<script type='application/json'>
  {JSON.stringify(
    {
      vars: {
        account: 'XX-XXXXXXXX-X',
      },
      requests: {
        experiment: `${pageview}&xid=${xid}&xvar=${xvar}`,
      },
    }
  )}
</script>

如果你这样做,React 足够聪明,知道script 标签中不需要 HTML 实体,所以那些&amp;s 不会被转义(不像它是一个普通的 HTML 元素,例如如div)。

您可以这样验证 (demo):

const InnerHtmlLogger = ({ TagName }) => {
  const ref = useRef(null);

  useEffect(() => {
    console.log(TagName, ref.current.innerHTML);
  }, [TagName]);

  return (
    <TagName ref={ref}>
      {JSON.stringify({
        '&': '&&',
        '&&&': ['&&&&', '&&&&&']
      })}
    </TagName>
  );
};

const App = () => {
  return (
    <>
      <InnerHtmlLogger TagName='div' />
      <InnerHtmlLogger TagName='script' />
    </>
  );
}

// Log output:
// div {"&amp;":"&amp;&amp;","&amp;&amp;&amp;":["&amp;&amp;&amp;&amp;","&amp;&amp;&amp;&amp;&amp;"]}
// script {"&":"&&","&&&":["&&&&","&&&&&"]}

【讨论】:

  • 事实证明,这是因为 Next.js 中的 AMP Optimizer — github.com/ampproject/amp-toolbox/pull/649 而现在我必须为这种情况找到解决方案
  • 即使不使用dangerouslySetInnerHTML,您能否确认您也有同样的问题?此外,考虑到JSON.parse(String.raw`"\u0026"`) === JSON.parse('"&amp;"'),在解析 JSON 时,使用\uXXXX 样式的序列进行转义应该没有任何区别。
  • 是的。所有你的变体都返回一个有效的 JSON,但是在我的带有 Next.js 的项目中,AMP Optimizer 中的 htmlEscape 在渲染之前会改变它——github.com/ampproject/amp-toolbox/pull/649/…
  • 这是否会使 JSON 解析不正确? JSON 的文字字符串表示可以在不影响其语义的情况下发生很大变化。例如,{ "a": "___", "a": "\u0026", "b": 1e+3 } 的解析方式应与 {"a":"&amp;","b":1000} 完全相同。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-17
  • 1970-01-01
  • 1970-01-01
  • 2013-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多