Flask模板渲染含HTML标签的变量被自动转义的解决方法
问题原因
效果不生效由两个问题共同导致:
- Flask默认搭载的Jinja2模板引擎默认开启HTML自动转义,会将
<、>这类HTML特殊字符转义为实体字符,你拼接的<mark>标签会被转成普通文本直接展示,不会被浏览器解析为DOM元素 <textarea>是纯文本输入控件,内部仅会原样展示纯文本内容,就算关闭转义,放在textarea里的HTML标签也不会渲染出高亮效果
解决步骤
1. 调整模板结构
不要把处理后的带标签内容放到textarea中,textarea仅用于接收用户原始输入,新增独立的普通块级元素(如div)展示高亮结果;同时对展示用的processed_text变量添加safe过滤器,告知模板引擎该内容可信,无需转义。
调整后的模板示例:
<div> <form action="/transform" method="post"> <!-- 输入区保留原始纯文本内容,不插入带HTML标签的处理后结果 --> <textarea name="text" cols="50" rows="10" style="margin:10px;">{{ original_text if original_text else '' }}</textarea> <br> <input type="text" name="keywords" placeholder="多个关键词用空格分隔" value="{{ keywords_text if keywords_text else '' }}"> <br> <button type="submit">生成高亮结果</button> </form> <!-- 高亮结果放在普通容器中,添加safe过滤器 --> <div style="margin:10px;padding:10px;border:1px solid #eee;"> 处理结果:{{ processed_text|safe }} </div> </div>
2. 优化后端逻辑(可选,提升鲁棒性)
对应模板调整,把用户原始输入的文本、关键词也传回模板用于回填输入框,同时补全空关键词过滤逻辑,避免连续空格产生空字符串导致正则匹配异常:
if request.method == "POST": text = request.form["text"] keywords_text = request.form["keywords"] # 过滤拆分后产生的空关键词,避免正则出现空匹配项导致全局异常包裹 keywords = [k.strip() for k in keywords_text.split(" ") if k.strip()] replacement = lambda match: f'<mark>{match.group()}</mark>' processed_text = re.sub("|".join(map(re.escape, keywords)), replacement, text, flags=re.I) return render_template( 'index.html', processed_text=processed_text, original_text=text, keywords_text=keywords_text )
注意事项
safe过滤器仅可用于后端可控、经过安全处理的内容,禁止直接给用户提交的未经过滤的原始内容添加该过滤器,避免引发XSS漏洞。- 非必要不要全局关闭模板的自动转义功能,默认转义是Flask提供的基础安全防护能力。
内容的提问来源于stack exchange,提问作者Saitama
相关产品推荐
相关产品推荐

