首页 > 解决方案 > 使用 eval 动态渲染从后端提供的 JSX

问题描述

我正在开发一个从 python JSON API 获取数据的 React 前端。我网站的一个部分包含优质内容,并为付费用户保留;目前,我通过将内容作为 JSON 对象获取并根据特定约定在前端将其转换为 JSX 来确保其他用户无法访问它。例如:

{
{ 'type': 'paragraph', 'value': 'some text'},
{ 'type': 'anchor', 'href': 'some url', 'value': 'some description'} 
}

将呈现为:

<p>some text</p>
<a href="some url">some description</a>

毫不奇怪,随着内容开始变得更有条理,事情开始变得相当复杂,像将部分文本加粗这样简单的事情需要不成比例的努力。

作为一个潜在的解决方案,我有一个想法:与其将内容作为对象发送并解析它,不如发送一个 JSX 字符串并在前端对其进行评估?

我是这样开始的:

import * as babel from "@babel/standalone";

export function renderFromString(code) {
  const transformed_code = babel.transform(code, {
    plugins: ["transform-react-jsx"]
  }).code;

    return eval(transformed_code);

}

我在我的高级内容页面中导入了这个函数,并尝试将完整的组件作为字符串传递(使用导入语句等),但由于找不到模块而出现错误。我认为发生这种情况是因为浏览器正在解释代码,因此它无法访问 node_modules?

作为一种解决方法,我尝试仅将标签传递给 renderFromString 并在已导入所有模块的组件的上下文中调用它:

import * as babel from "@babel/standalone";

export function renderFromString(code, context) {
  const _es5_code = babel.transform(code, {
    plugins: ["transform-react-jsx"]
  }).code;
  return function() {

    return eval(_es5_code);
  }.call(context);
}

这也失败了,因为 eval 似乎仍将在本地上下文中运行。

最后,我尝试执行与上述相同的操作,但直接在我的组件中执行 eval,而不是从我的函数中执行。只要我将“React”存储在一个变量中,它就可以工作 : import ReactModule from "react";const React = ReactModule,否则找不到它。

我的问题是:

  1. 有什么办法可以使我的前两种方法起作用吗?
  2. 我知道 eval 被认为是有害的,但由于内容始终是完全静态的并且来自我自己的服务器,所以我不明白这怎么会不安全。我错了吗?
  3. 我的问题有更好的解决方案吗?也就是说,一种在不更改我的单页应用程序 + JSON api 设置的情况下仅向某些用户安全地交付结构化内容的方法?

标签: javascriptnode.jsreactjs

解决方案


最好的解决方案是React 服务器端渲染

由于您需要与客户端兼容但同时通过 React 动态生成的标记,因此您可以将标记生成卸载到服务器。然后,服务器会将呈现的 HTML 发送到客户端以立即显示。

这是一篇关于 React SSR 以及它如何提高性能的好文章。


推荐阅读