如何在ReactElement中安全处理含#话题标签的文本并添加自定义HTML
安全处理含话题标签的文本渲染问题
我从数据库获取包含#话题标签的文本,需要将其作为<Post>元素的内部内容,希望把话题标签包装在<a>元素中,而不是直接作为纯文本传入<Post>。
目前我的实现方式如下:
function Post(props: Post) { // ... return( <div> {textPreprocessor(props.text)} </div> )} //... const textPreprocessor = (content : string) : React.ReactNode => { // adds hashtags let words = content.split(" "); let htmlString = "" words.forEach(word => { if(word[0] === "#") { htmlString += `<a href='hashtag/:${word}'/>${word}</a> ` } else{ htmlString += `${word} ` } }) return <div dangerouslySetInnerHTML={{__html: htmlString}} />; }
这个方案虽然能运行,但存在极高安全风险:数据库中的恶意HTML/JS代码会在前端执行。请问有没有更安全的实现方式?
安全实现方案
核心思路是彻底抛弃dangerouslySetInnerHTML,用React原生元素构建内容,利用React自动转义纯文本的特性规避注入风险。
方法1:拆分文本为React节点数组
通过正则拆分文本,将话题标签转为<a>元素,普通文本直接保留,组成React节点数组返回:
function Post(props: Post) { return ( <div> {textPreprocessor(props.text)} </div> ); } const textPreprocessor = (content: string): React.ReactNode[] => { // 正则匹配#开头的话题标签,可根据需求调整规则(比如支持中文标签) const hashtagRegex = /(#[\w\u4e00-\u9fa5]+)/g; // 拆分文本为「普通内容」和「话题标签」交替的数组 const contentParts = content.split(hashtagRegex); return contentParts.map((part, index) => { // 判断当前片段是否为话题标签 if (part.startsWith('#')) { return ( <a key={index} href={`hashtag/:${part}`} > {part} </a> ); } // 普通文本直接返回,React会自动转义<、>、&等特殊字符 return part; }); };
- 正则可按需调整,比如要支持带中文的标签,就把匹配规则改成
/#[\w\u4e00-\u9fa5]+/g - 用
split拆分后遍历数组,标签转成<a>,普通文本原样返回,完全不会触发恶意代码执行
方法2:用轻量库简化代码(可选)
如果需要同时处理@提及、表情等多种格式,可使用react-string-replace这类库简化逻辑,本质和方法1一致:
import replace from 'react-string-replace'; const textPreprocessor = (content: string): React.ReactNode => { return replace(content, /(#[\w\u4e00-\u9fa5]+)/g, (match, index) => ( <a key={index} href={`hashtag/:${match}`}> {match} </a> )); };
内容的提问来源于stack exchange,提问作者Null Salad
相关产品推荐
相关产品推荐

