在Flask中禁用自动转义

10 投票
3 回答
11453 浏览
提问于 2025-04-17 14:07

我想给用户显示一些文字。我要发送的字符串变量里面有很多换行符,但我不想让 \n 显示出来。所以我做了:

footext = """f
o
o"""

#footext == "f\no\no"

@app.route("/someurl")
def foo():
    return render_template("bar.html", text = footext.replace("\n", "<br />"))

bar.html :

<html>
{{ text }}
</html>

但是自动转义功能是开启的,我看到的内容是 f<br />o<br />o。而且我的方法也不安全,我希望除了 <br /> 标签外,其他所有标签都能被转义。我查看了 flask.Markup 模块,但它们似乎也不太管用。

那么,正确的做法是什么呢?

3 个回答

1

在Jinja2模板中,可以选择关闭自动转义功能,或者使用原始块

6

我会把我之前的回答当作一个不好的例子。

对于这种情况,一个很好的解决办法是使用自定义过滤器,这样你就可以使用类似下面的语法:

{{ block_of_text | nl2br }}

而且,方便的是,你可以用这个nl2br过滤器代码片段(或者轻松自定义)来实现!

9

你可以采取两种合理的方法。

解决方案 1

因为你要把不安全的输入和 HTML 合并到一个变量中,使用 flask.Markup 实际上是个很方便的办法。基本的思路是把你的文本按换行符分开,确保对每一行你不信任的内容进行 HTML 转义,然后再用你信任的 <br /> 标签把它们拼接起来。

下面是一个完整的应用示例来演示这个方法。它使用了和你问题中一样的 bar.html 模板。注意,我在 footext 中添加了一些不安全的 HTML,来说明为什么关闭自动转义并不是一个安全的解决方案。

import flask

app = flask.Flask(__name__)

footext = """f
o
<script>alert('oops')</script>
o"""


@app.route("/foo")
def foo():
    text = ""
    for line in footext.split('\n'):
        text += flask.Markup.escape(line) + flask.Markup('<br />')
    return flask.render_template("bar.html", text=text)

if __name__ == "__main__":
    app.run(debug=True)

解决方案 2

另一个选择是把复杂的部分放到模板中,这样你就能得到一个更简单的视图。只需将 footext 按行分开,然后在模板中循环处理,自动转义就会帮你确保安全。

更简单的视图:

@app.route("/foo")
def foo():
    return flask.render_template("bar.html", text=footext.split('\n'))

模板 bar.html 变成:

<html>
    {%- for line in text -%}
        {{ line }}
        {%- if not loop.last -%}
            <br />
        {%- endif -%}
    {%- endfor -%}
</html>

总结

我个人更喜欢解决方案 2,因为它把渲染的细节(行之间用 <br /> 标签分隔)放在了模板中,这样更合适。如果将来你想把这些行改成用项目符号列表显示,你只需要修改模板,而不是代码。

撰写回答