使用golang标准库中的html/template
时,在默认情况下渲染模版时为了安全等原因,会将字符串中的部分符号进行转义。例如在下面的例子中,我们定义了一个简单的HTML模版:
<body>
<main>
{{.Content}}
</main>
</body>
我们直接使用默认设置,并传入带有HTML标签的文本进行渲染:
// content内容为上面的模版
// var content string
tpl, err := template.New("example").Parse(content)
if err != nil {
// ...
}
buf := new(bytes.Buffer)
tpl.Execute(buf, map[string]string{
"Content": "<p>Hello, world!</p>",
})
在这样的情况下,上述内容将被转义并最终得到下面的文本,而非期望中嵌入带有HTML标签的文本:
<body>
<main>
<p>Hello World</p>
</main>
</body>
传递template.HTML类型值避免转义
为了实现避免转义的效果,可以在执行Execute()
方法前,将带有HTML标签的文本转为template.HTML
类型:
tpl.Execute(buf, map[string]any{
"Content": template.HTML("<p>Hello, world!</p>"),
})
使用这种方法实现最为简单,但缺陷是在不修改代码的情况下该字段将固定转换为template.HTML
类型,使用较为不灵活。
注册自定义转义处理函数
除了在执行Execute()
前将文本转换类型外,还可以使用模版的Funcs()
方法注册自定义函数。
为了实现我们避免转义HTML文本的效果,我们先要定义一个函数用于处理将字符串转为template.HTML
类型。例如我们定一个名为unescapeHTML
的函数:
func unescapeHTML(s string) template.HTML {
return template.HTML(s)
}
在定义转义处理函数后,我们需要使用Funcs()
将其注册到模版中。需要注意,注册自定义函数需要在调用Parse()
前进行。在注册时我们需要定义一个函数标识符,并在模版文本中使用。在下面例子中我们使用了名为unescapeHTML
的函数标识符。
tpl, err := template.
New("example").
Funcs(template.FuncMap{
"unescapeHTML": unescapeHTML,
}).
Parse(content)
if err != nil {
// ...
}
buf := new(bytes.Buffer)
tpl.Execute(buf, map[string]string{
"Content": "<p>Hello, world!</p>",
})
另外在模版文本内容中,对于需要避免转义的部分需要使用上面定义的函数。为了进行对比,我们在示例中对两个区域分别使用了unescapeHTML
进行标记以及不使用任何修改:
<body>
<main>
<div>{{unescapeHTML .Content}}</div>
<div>{{.Content}}</div>
</main>
</body>
执行后我们将得到:
<body>
<main>
<div><p>Hello, world!</p></div>
<div><p>Hello, world!</p></div>
</main>
</body>
写在最后
使用模版的自定义函数自定义转义处理方法虽相对将为复杂一些,但是在后续使用中较为灵活,只需要修改模版文件即可,而无需修改实现代码。
html/template
同样也提供了例如template.JS
、template.CSS
等类型,用于Javascript或是CSS的处理。
html/template
包默认进行转义很大程度上避免了一些安全性的问题,例如潜在的XSS攻击等。在实际使用中,进行不转义处理后将存在安全性方面的风险,对于风险较高的使用场合需要另外考虑这方面的处理。