Gahing's blog Gahing's blog
首页
知识体系
  • 前端基础
  • 应用框架
  • 工程能力
  • 应用基础
  • 专业领域
  • 业务场景
  • 前端晋升 (opens new window)
  • Git
  • 网络基础
  • 算法
  • 数据结构
  • 编程范式
  • 编解码
  • Linux
  • AIGC
  • 其他领域

    • 客户端
    • 服务端
    • 产品设计
软素质
  • 面试经验
  • 人生总结
  • 个人简历
  • 知识卡片
  • 灵感记录
  • 实用技巧
  • 知识科普
  • 友情链接
  • 美食推荐 (opens new window)
  • 收藏夹

    • 优质前端信息源 (opens new window)
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Gahing / francecil

To be best
首页
知识体系
  • 前端基础
  • 应用框架
  • 工程能力
  • 应用基础
  • 专业领域
  • 业务场景
  • 前端晋升 (opens new window)
  • Git
  • 网络基础
  • 算法
  • 数据结构
  • 编程范式
  • 编解码
  • Linux
  • AIGC
  • 其他领域

    • 客户端
    • 服务端
    • 产品设计
软素质
  • 面试经验
  • 人生总结
  • 个人简历
  • 知识卡片
  • 灵感记录
  • 实用技巧
  • 知识科普
  • 友情链接
  • 美食推荐 (opens new window)
  • 收藏夹

    • 优质前端信息源 (opens new window)
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 前端基础

  • 应用框架

    • UI 框架

      • Angular

      • React

        • React Hooks 实现原理
        • React 组件销毁需要注意的异步更新问题
        • React项目结构规范
        • React Fiber 实现原理
        • React Fiber 本质
        • React「 Refs 转发 」初探
        • React之低版本chrome setState loading2次状态出现的bug
        • react学习
        • 使用 immer 修改复杂对象
        • input 原生控件,React 是如何实现受控输入的?
        • useEffect 如何处理 async
        • 用组件替换文本中emoji字符
          • 背景
          • 简单粗暴的做法 dangerouslySetInnerHTML
          • 安全的做法
          • 在线 demo
          • 后端方案
          • 参考资料
        • 谈谈 React 组件设计原则
      • Solid

      • Svelte

      • Vue

      • 框架本质

    • 开发框架

    • 组件库

  • 工程能力

  • 应用基础

  • 专业领域

  • 业务场景

  • 大前端
  • 应用框架
  • UI 框架
  • React
gahing
2020-07-14
目录

用组件替换文本中emoji字符

# 背景

需要将用户输入的内容进行展现,其中某些字符会被替换为预定义好的的表情图片。

注意安全漏洞

# 简单粗暴的做法 dangerouslySetInnerHTML

import React from "react";

const emojiMap = {
  "[aa]": "a.jpg",
  "[bb]": "b.jpg"
};
const DangerouslyRender = ({ text }) => {
  let regex = /\[\S+?\]/g;
  const allEmoji = Object.keys(emojiMap);
  text = text.replace(regex, match => {
    if (allEmoji.includes(match)) {
      return `<img class='emoji_icon' src='${emojiMap[match]}'/>`;
    }
    return match;
  });
  return (
    <pre
      dangerouslySetInnerHTML={{
        __html: text
      }}
    />
  );
};
export default function App() {
  const text = "hhh,b[aa]tt<img src=a onerror=alert(1)>[bb]";
  return (
    <div className="App">
      <DangerouslyRender text={text} />
    </div>
  );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

存在的问题: XSS 漏洞

# 安全的做法

利用 split 进行分割,注意这里的正则相比之前多了括号,可以保留分割字符,用于后续替换

"asdsd[aa],[bb]ss".split(/\[\S+?\]/g) //  ["asdsd", ",", "ss"]
"asdsd[aa],[bb]ss".split(/(\[\S+?\])/g) //  ["asdsd", "[aa]", ",", "[bb]", "ss"]
1
2

得到分割数组后,就可以随意处理了,比如 for of 输出,或者用 map ,示例如下

const content = text.split(regex).map((current) => {
    if (allEmoji.includes(current)) {
      return <img className="emoji_icon" src={emojiMap[current]} alt={current} />
    }
    return current
});
1
2
3
4
5
6

或者用 reduce ,完整代码如下:

import React from "react";

const emojiMap = {
  "[aa]": "a.jpg",
  "[bb]": "b.jpg"
};
const SafeRender = ({ text }) => {
  const allEmoji = Object.keys(emojiMap);
  const regex = /(\[\S+?\])/g;
  const content = text.split(regex).reduce((prev, current) => {
    let target = current;
    if (allEmoji.includes(current)) {
      target = (
        <img className="emoji_icon" src={emojiMap[current]} alt={current} />
      );
    }
    return prev.concat(target);
  }, []);
  console.log({ text, content });
  return content;
};
export default function App() {
  const text = "hhh,b[aa]tt<img src=a onerror=alert(1)>[bb]";
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <SafeRender text={text} />
    </div>
  );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 在线 demo

https://codesandbox.io/s/tender-blackburn-6d9o2?file=/src/App.js

# 后端方案

后端过滤,评论成功后返回过滤后的内容

此时前端是否用 dangerouslySetInnerHTML 还是自己构造组件都无所谓了

# 参考资料

How to replace parts of a string with a component?#3386 (opens new window)

编辑 (opens new window)
#React
上次更新: 2024/09/01, 23:56:56
useEffect 如何处理 async
谈谈 React 组件设计原则

← useEffect 如何处理 async 谈谈 React 组件设计原则→

最近更新
01
浅谈代码质量与量化指标
08-27
02
快速理解 JS 装饰器
08-26
03
Vue 项目中的 data-v-xxx 是怎么生成的
09-19
更多文章>
Theme by Vdoing | Copyright © 2016-2024 Gahing | 闽ICP备19024221号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式