我有一个简单的Go HTML模板,其中包含HTML条件注释:
package main
import (
"html/template"
"os"
)
var body = `<!doctype html>
<html>
<head>
<!--[if !IE]><!--><script src="http://code.jquery.com/jquery-2.0.3.min.js"></script><!--<![endif]-->
<!--[if gte IE 9]><script src="http://code.jquery.com/jquery-2.0.3.min.js"></script><![endif]-->
<!--[if lt IE 9]><script src="http://code.jquery.com/jquery-1.10.2.min.js"></script><![endif]-->
</head>
</html>`
func main() {
tmp := template.Must(template.New("tmp").Parse(body))
tmp.Execute(os.Stdout, nil)
}
Run Code Online (Sandbox Code Playgroud)
<!doctype html>
<html>
<head>
<script src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
</head>
</html>
Run Code Online (Sandbox Code Playgroud)
为什么html/template在编译后删除那些条件注释?
我的解决方法是重新实现在提交#938597eab997上删除的noescape帮助程序
funcMap := template.FuncMap{
"noescape": func(s string) template.HTML {
return template.HTML(s)
},
}
Run Code Online (Sandbox Code Playgroud)
然后在您的模板中使用它:
<!DOCTYPE html>
{{noescape "<!--[if lt IE 9]>"}}<html class="old-ie">{{noescape "<![endif]-->"}}
Run Code Online (Sandbox Code Playgroud)
既然你的问题是为什么,我会试着解释为什么评论被剥夺了.
首先,html/template包装的目的是安全的.该文件规定:
包模板(html/template)实现了数据驱动的模板,用于生成HTML输出,以防止代码注入.
这是通过上下文敏感的转义来完成的.在Golang-nuts线程中, Kyle Lemons提供了一个示例,其中条件注释目前会破坏此安全性,除非评论被删除:
<p>
<!--[if lt IE 9]><script><![endif]-->
{{.Stuff}}
<!--[if lt IE 9]></script><![endif]-->
</p>
Run Code Online (Sandbox Code Playgroud)
在这种情况下,{{.Stuff}}中的任何值都将在某些浏览器上作为Javascript执行,因此应该被转义为安全的.这将要求模板引擎知道注释的这种特定于浏览器的解释,以及所有浏览器中的任何其他非标准行为.这是不可行的.
相反,html/template它旨在去除任何注释,以确保它产生的HTML对任何注入攻击都是安全的.
解决方法
如Dave所述,可以使用template.HTML插入此类注释.然而,由于安全风险,该文档的template.HTML状态(我的重点):
HTML封装了一个已知的安全HTML文档片段.它不应该用于来自第三方的HTML,也不能用于带有未关闭标签或注释的 HTML .