如何在react中嵌入后端返回的html文本

5,354 阅读2分钟

这是我参与11月更文挑战的第1天,活动详情查看:11月更文挑战

前言:

在一次与第三方对接的过程中,向后端发起了一个请求,他直接返回了一个html,然后需要展示到页面上。于是展开了下面的行动。

dangerouslySetInnerHTML

dangerouslySetInnerHTML 是 React 为浏览器 DOM 提供 innerHTML 的替换方案。通常来讲,使用代码直接设置 HTML 存在风险,因为很容易无意中使用户暴露于跨站脚本(XSS)的攻击。因此,你可以直接在 React 中设置 HTML,但当你想设置 dangerouslySetInnerHTML 时,需要向其传递包含 key 为 __html 的对象,以此来警示你。例如:

function createMarkup() {
  return {__html: 'First · Second'};
}

function MyComponent() {
  return <div dangerouslySetInnerHTML={createMarkup()} />;
}

在了解到这个属性以后,我直接三下五除二,就直接一手复制。大致代码如下。

// 请求部分去取到回填htmlText 变量中

// react return 
      <div dangerouslySetInnerHTML={{ __html: htmlText }}></div>

虽然页面展示出来了,但是还有几个问题,js没法加载,以及script里面的js也没有执行。于是我就先做了最简单的尝试,我把htmlText换成了如下的代码.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script type="text/javascript">
        console.log('test---');
    </script>
    <div>test</div>
</body>
</html>

这个html就是一个div,然后会打印console.log。然后发现,这个代码的console也打印不出来,于是我猜想dangerouslySetInnerHTML可能就只是把html直接加进入,script是不会解析的。于是这个办法没辙,只能另寻他法。

iframe

于是我想到了iframe,这个可以直接内嵌网页的好东西。但是我这次需要发起的请求是post,传统我们了解到的iframe都是默认是get请求。那如何去做post请求呢,果然google上好东西,大家之前都有过探索了。

结合form表单,利用form表单的post请求方式达到目的,实现方式如下

实现方式 增加一个form表单的标签,method设置为post,target设置一个标识,假如target=”target1” 在iframe设置name属性,name需要与target一致 name = “target1”

发送请求时通过发送form submit请求来使用post方式

html代码

<div>
    <form id="form1" action="" target="target1" method="post"></form>
    <iframe id="xxx" name="target1" src=""></iframe>
</div>

具体在react中的实现如下。


import { isOrdinaryCompany } from '@/common/project';
import { message, Result, Spin } from 'antd';
import React, { useEffect } from 'react';

export default () => {

  const handleClick = () => {
    dispatch({
      type: 'insurance/fetchPcOrganizeDockingInsurance',
      payload: {
        creditCode: currentUser?.creditCode || '',
      },
    })
      .then((res) => {
        const r = JSON.parse(res);
        // 将参数回填至表单最终提交
        const { ediparam = '', edisign = '' } = r;
        document.getElementById('ediparam').value = ediparam;
        document.getElementById('edisign').value = edisign;
        document.getElementById('form1').submit();
      })
      .catch((err) => {
        message.error(err);
      });
  };

  useEffect(() => {
    if (isOrdinaryCompany()) {
      handleClick();
    }
  }, []);

  return (
    <>
        <div>
          <Spin spinning={loading}>
            <form
              id="form1"
              action={`${window.location.origin}/ProjectInsurance/gateway.do`}
              target="target1"
              method="post"
            >
              <input id="edisign" name="edisign" value="隐藏域" type="hidden" />
              <input id="ediparam" name="ediparam" value="隐藏域" type="hidden" />
            </form>
            <iframe
              id="xxx"
              name="target1"
              src=""
              width="100%"
              height="500"
              title="红绿灯"
              frameBorder="no"
            />
          </Spin>
        </div>
    </>
  );
};

最终的效果

iframe嵌入成功。 image.png

参考:

blog.csdn.net/slh2016/art…