企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
{% raw %} # package template `import "html/template"` template包(html/template)实现了数据驱动的模板,用于生成可对抗代码注入的安全HTML输出。本包提供了和text/template包相同的接口,无论何时当输出是HTML的时候都应使用本包。 此处的文档关注本包的安全特性。至于如何使用模板,请参照text/template包。 ### Introduction 本包是对[text/template](http://godoc.org/text/template)包的包装,两个包提供的模板API几无差别,可以安全的随意替换两包。 ``` tmpl, err := template.New("name").Parse(...) // 省略错误检测 err = tmpl.Execute(out, data) ``` 如果成功创建了tmpl,tmpl现在是注入安全的了。否则err将返回ErrorCode里定义的某个错误。即使成功生成了模板,执行时仍可能导致ErrorCode里定义的错误。 HTML模板将数据视为明文文本,必须经过编码以便安全的嵌入HTML文档。转义操作会参考上下文,因此action可以出现在JavaScript、CSS、URI上下文环境里。 本包使用的安全模型假设模板的作者是可信任的,但用于执行的数据不可信。更多细节参见下面。 示例: ``` import "text/template" ... t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`) err = t.ExecuteTemplate(out, "T", "<script>alert('you have been pwned')</script>") ``` 生成: ``` Hello, <script>alert('you have been pwned')</script>! ``` 但在html/template包里会根据上下文自动转义: ``` import "html/template" ... t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`) err = t.ExecuteTemplate(out, "T", "<script>alert('you have been pwned')</script>") ``` 生成安全的转义后HTML输出: ``` Hello, &lt;script&gt;alert(&#39;you have been pwned&#39;)&lt;/script&gt;! ``` ### Contexts 本包可以理解HTML、CSS、JavaScript和URI。它会给每一个简单的action pipeline都添加处理函数,如下例: ``` <a href="/search?q={{.}}">{{.}}</a> ``` 在解析时每个{{.}}都会在必要时重写添加转义函数,此例中会修改为: ``` <a href="/search?q={{. | urlquery}}">{{. | html}}</a> ``` ### Errors 细节请参见ErrorCode类型的文档。 ### A fuller picture 本包剩余部分的注释第一次阅读时可以跳过;这些部分包括理解转码文本和错误信息的必要细节。多数使用者无需理解这些细节。 ### Contexts 假设{{.}}是`O'Reilly: How are &lt;i&gt;you&lt;/i&gt;?`,下表展示了{{.}}用于左侧模板时的输出: ``` Context {{.}} After {{.}} O'Reilly: How are &lt;i&gt;you&lt;/i&gt;? <a title='{{.}}'> O&#39;Reilly: How are you? <a href="/{{.}}"> O&#39;Reilly: How are %3ci%3eyou%3c/i%3e? <a href="?q={{.}}"> O&#39;Reilly%3a%20How%20are%3ci%3e...%3f <a onx='f("{{.}}")'> O\x27Reilly: How are \x3ci\x3eyou...? <a onx='f({{.}})'> "O\x27Reilly: How are \x3ci\x3eyou...?" <a onx='pattern = /{{.}}/;'> O\x27Reilly: How are \x3ci\x3eyou...\x3f ``` 如果用在不安全的上下文里,值就可能被过滤掉: ``` Context {{.}} After <a href="{{.}}"> #ZgotmplZ ``` 因为"O'Reilly:"不是一个可以接受的协议名,如"http:"。 如果{{.}}是一个无害的词汇,如`left`,那么它就可以出现在更多地方。 ``` Context {{.}} After {{.}} left <a title='{{.}}'> left <a href='{{.}}'> left <a href='/{{.}}'> left <a href='?dir={{.}}'> left <a style="border-{{.}}: 4px"> left <a style="align: {{.}}"> left <a style="background: '{{.}}'> left <a style="background: url('{{.}}')> left <style>p.{{.}} {color:red}</style> left ``` 如果{{.}}是非字符串类型的值,可以用于JavaScript上下文环境里: ``` struct{A,B string}{ "foo", "bar" } ``` 将该值应用在在转义后的模板里: ``` <script>var pair = {{.}};</script> ``` 模板输出为: ``` <script>var pair = {"A": "foo", "B": "bar"};</script> ``` 请参见json包来理解非字符串内容是如何序列化并嵌入JavaScript里的。 ### Typed Strings 本包默认所有的pipeline都生成明文字符串,它会在必要时添加转义pipeline阶段以安全并正确的将明文字符串嵌入输出的文本里。 当用于执行的数据不是明文字符串时,你可以通过显式改变数据的类型以避免其被错误的转义。 类型HTML、JS、URL和其他content.go里定义的类型可以保持不被转义的安全内容。 模板: ``` Hello, {{.}}! ``` 可以采用如下调用: ``` tmpl.Execute(out, HTML(`<b>World</b>`)) ``` 来输出: ``` Hello, <b>World</b>! ``` 而不是: ``` Hello, &lt;b&gt;World&lt;b&gt;! ``` 如果{{.}}是一个内建类型字符串就会产生该输出。 ### Security Model 本包里安全的定义参加如下网页: [http://js-quasis-libraries-and-repl.googlecode.com/svn/trunk/safetemplate.html#problem_definition](http://js-quasis-libraries-and-repl.googlecode.com/svn/trunk/safetemplate.html#problem_definition) 本包假设模板作者可信而执行数据不可信,目标是在保证安全性的前提下保证效率: 结构保留特性:“……当模板作者用安全的模板语言写了一个HTML标签时,不管数据的值为何浏览器都会将输出的相应部分解释为标签,该情况在其他结构里也成立,如属性边界以及JS和CSS边界。” 代码影响特性:“……只有模板作者指定的代码能作为注入模板输出到页面的结果执行,所有模板作者指定的代码都应如此。” 最少惊讶特性:“一个熟悉HTML、CSS、JS的开发者(或代码阅读者),应可以正确的推断出{{.}}会如何转义。” ## Index * [type ErrorCode](#ErrorCode) * [type Error](#Error) * [func (e \*Error) Error() string](#Error.Error) * [func HTMLEscape(w io.Writer, b []byte)](#HTMLEscape) * [func HTMLEscapeString(s string) string](#HTMLEscapeString) * [func HTMLEscaper(args ...interface{}) string](#HTMLEscaper) * [func JSEscape(w io.Writer, b []byte)](#JSEscape) * [func JSEscapeString(s string) string](#JSEscapeString) * [func JSEscaper(args ...interface{}) string](#JSEscaper) * [func URLQueryEscaper(args ...interface{}) string](#URLQueryEscaper) * [type FuncMap](#FuncMap) * [type HTML](#HTML) * [type HTMLAttr](#HTMLAttr) * [type JS](#JS) * [type JSStr](#JSStr) * [type CSS](#CSS) * [type URL](#URL) * [type Template](#Template) * [func Must(t \*Template, err error) \*Template](#Must) * [func New(name string) \*Template](#New) * [func ParseFiles(filenames ...string) (\*Template, error)](#ParseFiles) * [func ParseGlob(pattern string) (\*Template, error)](#ParseGlob) * [func (t \*Template) Name() string](#Template.Name) * [func (t \*Template) Delims(left, right string) \*Template](#Template.Delims) * [func (t \*Template) Funcs(funcMap FuncMap) \*Template](#Template.Funcs) * [func (t \*Template) Clone() (\*Template, error)](#Template.Clone) * [func (t \*Template) Lookup(name string) \*Template](#Template.Lookup) * [func (t \*Template) Templates() []\*Template](#Template.Templates) * [func (t \*Template) New(name string) \*Template](#Template.New) * [func (t \*Template) AddParseTree(name string, tree \*parse.Tree) (\*Template, error)](#Template.AddParseTree) * [func (t \*Template) Parse(src string) (\*Template, error)](#Template.Parse) * [func (t \*Template) ParseFiles(filenames ...string) (\*Template, error)](#Template.ParseFiles) * [func (t \*Template) ParseGlob(pattern string) (\*Template, error)](#Template.ParseGlob) * [func (t \*Template) Execute(wr io.Writer, data interface{}) error](#Template.Execute) * [func (t \*Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error](#Template.ExecuteTemplate) ## type [ErrorCode](https://github.com/golang/go/blob/master/src/html/template/error.go#L24 "View Source") ``` type ErrorCode int ``` ErrorCode是代表错误种类的错误码。 ``` const ( // OK表示没有出错 OK ErrorCode = iota // 当上下文环境有歧义时导致ErrAmbigContext: // 举例: // <a href="{{if .C}}/path/{{else}}/search?q={{end}}{{.X}}"&rt; // 说明: // {{.X}}的URL上下文环境有歧义,因为根据{{.C}}的值, // 它可以是URL的后缀,或者是查询的参数。 // 将{{.X}}移动到如下情况可以消除歧义: // <a href="{{if .C}}/path/{{.X}}{{else}}/search?q={{.X}}{{end}}"&rt; ErrAmbigContext // 期望空白、属性名、标签结束标志而没有时,标签名或无引号标签值包含非法字符时, // 会导致ErrBadHTML;举例: // <a href = /search?q=foo&rt; // <href=foo&rt; // <form na<e=...&rt; // <option selected< // 讨论: // 一般是因为HTML元素输入了错误的标签名、属性名或者未用引号的属性值,导致解析失败 // 将所有的属性都用引号括起来是最好的策略 ErrBadHTML // {{if}}等分支不在相同上下文开始和结束时,导致ErrBranchEnd // 示例: // {{if .C}}<a href="{{end}}{{.X}} // 讨论: // html/template包会静态的检验{{if}}、{{range}}或{{with}}的每一个分支, // 以对后续的pipeline进行转义。该例出现了歧义,{{.X}}可能是HTML文本节点, // 或者是HTML属性值的URL的前缀,{{.X}}的上下文环境可以确定如何转义,但该 // 上下文环境却是由运行时{{.C}}的值决定的,不能在编译期获知。 // 这种问题一般是因为缺少引号或者角括号引起的,另一些则可以通过重构将两个上下文 // 放进if、range、with的不同分支里来避免,如果问题出现在参数长度一定非0的 // {{range}}的分支里,可以通过添加无效{{else}}分支解决。 ErrBranchEnd // 如果以非文本上下文结束,则导致ErrEndContext // 示例: // <div // <div title="no close quote&rt; // <script>f() // 讨论: // 执行模板必须生成HTML的一个文档片段,以未闭合标签结束的模板都会引发本错误。 // 不用在HTML上下文或者生成不完整片段的模板不应直接执行。 // {{define "main"}} <script&rt;{{template "helper"}}</script> {{end}} // {{define "helper"}} document.write(' <div title=" ') {{end}} // 模板"helper"不能生成合法的文档片段,所以不直接执行,用js生成。 ErrEndContext // 调用不存在的模板时导致ErrNoSuchTemplate // 示例: // {{define "main"}}<div {{template "attrs"}}&rt;{{end}} // {{define "attrs"}}href="{{.URL}}"{{end}} // 讨论: // html/template包略过模板调用计算上下文环境。 // 此例中,当被"main"模板调用时,"attrs"模板的{{.URL}}必须视为一个URL; // 但如果解析"main"时,"attrs"还未被定义,就会导致本错误 ErrNoSuchTemplate // 不能计算输出位置的上下文环境时,导致ErrOutputContext // 示例: // {{define "t"}}{{if .T}}{{template "t" .T}}{{end}}{{.H}}",{{end}} // 讨论: // 一个递归的模板,其起始和结束的上下文环境不同时; // 不能计算出可信的输出位置上下文环境时,就可能导致本错误。 // 检查各个命名模板是否有错误; // 如果模板不应在命名的起始上下文环境调用,检查在不期望上下文环境中对该模板的调用; // 或者将递归模板重构为非递归模板; ErrOutputContext // 尚未支持JS正则表达式插入字符集 // 示例: // <script>var pattern = /foo[{{.Chars}}]/</script&rt; // 讨论: // html/template不支持向JS正则表达式里插入字面值字符集 ErrPartialCharset // 部分转义序列尚未支持 // 示例: // <script>alert("\{{.X}}")</script&rt; // 讨论: // html/template包不支持紧跟在反斜杠后面的action // 这一般是错误的,有更好的解决方法,例如: // <script>alert("{{.X}}")</script&rt; // 可以工作,如果{{.X}}是部分转义序列,如"xA0", // 可以将整个序列标记为安全文本:JSStr(`\xA0`) ErrPartialEscape // range循环的重入口出错,导致ErrRangeLoopReentry // 示例: // <script>var x = [{{range .}}'{{.}},{{end}}]</script&rt; // 讨论: // 如果range的迭代部分导致其结束于上一次循环的另一上下文,将不会有唯一的上下文环境 // 此例中,缺少一个引号,因此无法确定{{.}}是存在于一个JS字符串里,还是一个JS值文本里。 // 第二次迭代生成类似下面的输出: // <script>var x = ['firstValue,'secondValue]</script&rt; ErrRangeLoopReentry // 斜杠可以开始一个除法或者正则表达式 // 示例: // <script&rt; // {{if .C}}var x = 1{{end}} // /-{{.N}}/i.test(x) ? doThis : doThat(); // </script&rt; // 讨论: // 上例可以生成`var x = 1/-2/i.test(s)...`,其中第一个斜杠作为除号; // 或者它也可以生成`/-2/i.test(s)`,其中第一个斜杠生成一个正则表达式字面值 // 检查分支中是否缺少分号,或者使用括号来明确你的意图 ErrSlashAmbig ) ``` 我们为转义模板时的所有错误都定义了错误码,但经过转义修正的模板仍可能在运行时出错: 输出"ZgotmplZ"的例子: ``` <img src="{{.X}}"> 其中{{.X}}执行结果为`javascript:...` ``` 讨论: ``` "ZgotmplZ"是一个特殊值,表示运行时在CSS或URL上下文环境生成的不安全内容。本例的输出为: <img src="#ZgotmplZ"> 如果数据来源可信,请转换内容类型来避免被滤除:URL(`javascript:...`) ``` ## type [Error](https://github.com/golang/go/blob/master/src/html/template/error.go#L12 "View Source") ``` type Error struct { // ErrorCode描述错误的种类 ErrorCode ErrorCode // Name是发生错误的模板的名字 Name string // Line是错误位置在模板原文中的行号或者0 Line int // Description是供调试者阅读的错误描述 Description string } ``` Error描述在模板转义时出现的错误。 ### func (\*Error) [Error](https://github.com/golang/go/blob/master/src/html/template/error.go#L184 "View Source") ``` func (e *Error) Error() string ``` ## func [HTMLEscape](https://github.com/golang/go/blob/master/src/html/template/escape.go#L780 "View Source") ``` func HTMLEscape(w io.Writer, b []byte) ``` 函数向w中写入b的HTML转义等价表示。 ## func [HTMLEscapeString](https://github.com/golang/go/blob/master/src/html/template/escape.go#L785 "View Source") ``` func HTMLEscapeString(s string) string ``` 返回s的HTML转义等价表示字符串。 ## func [HTMLEscaper](https://github.com/golang/go/blob/master/src/html/template/escape.go#L791 "View Source") ``` func HTMLEscaper(args ...interface{}) string ``` 函数返回其所有参数文本表示的HTML转义等价表示字符串。 ## func [JSEscape](https://github.com/golang/go/blob/master/src/html/template/escape.go#L796 "View Source") ``` func JSEscape(w io.Writer, b []byte) ``` 函数向w中写入b的JavaScript转义等价表示。 ## func [JSEscapeString](https://github.com/golang/go/blob/master/src/html/template/escape.go#L801 "View Source") ``` func JSEscapeString(s string) string ``` 返回s的JavaScript转义等价表示字符串。 ## func [JSEscaper](https://github.com/golang/go/blob/master/src/html/template/escape.go#L807 "View Source") ``` func JSEscaper(args ...interface{}) string ``` 函数返回其所有参数文本表示的JavaScript转义等价表示字符串。 ## func [URLQueryEscaper](https://github.com/golang/go/blob/master/src/html/template/escape.go#L813 "View Source") ``` func URLQueryEscaper(args ...interface{}) string ``` 函数返回其所有参数文本表示的可以嵌入URL查询的转义等价表示字符串。 ## type [FuncMap](https://github.com/golang/go/blob/master/src/html/template/template.go#L261 "View Source") ``` type FuncMap map[string]interface{} ``` FuncMap类型定义了函数名字符串到函数的映射,每个函数都必须有1到2个返回值,如果有2个则后一个必须是error接口类型;如果有2个返回值的方法返回的error非nil,模板执行会中断并返回给调用者该错误。该类型拷贝自text/template包的同名类型,因此不需要导入该包以使用该类型。 ## type [HTML](https://github.com/golang/go/blob/master/src/html/template/content.go#L27 "View Source") ``` type HTML string ``` HTML用于封装一个已知安全的HTML文档片段。它不应被第三方使用,也不能用于含有未闭合的标签或注释的HTML文本。该类型适用于封装一个效果良好的HTML生成器生成的HTML文本或者本包模板的输出的文本。 ## type [HTMLAttr](https://github.com/golang/go/blob/master/src/html/template/content.go#L31 "View Source") ``` type HTMLAttr string ``` HTMLAttr用来封装一个来源可信的HTML属性,如` dir="ltr"`。 ## type [JS](https://github.com/golang/go/blob/master/src/html/template/content.go#L40 "View Source") ``` type JS string ``` JS用于封装一个已知安全的EcmaScript5表达式,如`(x + y * z())`。模板作者有责任确保封装的字符串不会破坏原有的语义,也不能包含有歧义的声明或表达式,如"{ foo: bar() }\n['foo']()",这一句既是合法的表达式也是语义完全不同的合法程序。 ## type [JSStr](https://github.com/golang/go/blob/master/src/html/template/content.go#L49 "View Source") ``` type JSStr string ``` JSStr用于封装一个打算嵌入JavaScript表达式中的字符序列,该字符串必须匹配一系列StringCharacters: ``` StringCharacter :: 除了`\`和行终止符的SourceCharacter | EscapeSequence ``` 注意不允许换行,JSStr("foo\\nbar")是可以的,但JSStr("foo\\\nbar")不可以。 ## type [URL](https://github.com/golang/go/blob/master/src/html/template/content.go#L56 "View Source") ``` type URL string ``` URL用来封装一个已知安全的URL或URL子字符串(参见[RFC 3986](http://tools.ietf.org/html/rfc3986)) 形如`javascript:checkThatFormNotEditedBeforeLeavingPage()`的来源可信的URL应写进页面里,但一般动态的`javascript:` URL排除在外(不写进页面),因为它们是频繁使用的注入向量。 ## type [CSS](https://github.com/golang/go/blob/master/src/html/template/content.go#L21 "View Source") ``` type CSS string ``` CSS用于包装匹配如下任一条的已知安全的内容: ``` 1\. CSS3样式表,如`p { color: purple }` 2\. CSS3规则,如`a[href=~"https:"].foo#bar` 3\. CSS3声明,如`color: red; margin: 2px` 4\. CSS3规则,如`rgba(0, 0, 255, 127)` ``` 参见:[http://www.w3.org/TR/css3-syntax/#parsing](http://www.w3.org/TR/css3-syntax/#parsing)  以及:[https://web.archive.org/web/20090211114933/http://w3.org/TR/css3-syntax#style](https://web.archive.org/web/20090211114933/http:/w3.org/TR/css3-syntax#style) ## type [Template](https://github.com/golang/go/blob/master/src/html/template/template.go#L19 "View Source") ``` type Template struct { // 底层的模板解析树,会更新为HTML安全的 Tree *parse.Tree // 内含隐藏或非导出字段 } ``` Template类型是text/template包的Template类型的特化版本,用于生成安全的HTML文本片段。 ### func [Must](https://github.com/golang/go/blob/master/src/html/template/template.go#L294 "View Source") ``` func Must(t *Template, err error) *Template ``` Must函数用于包装返回(\*Template, error)的函数/方法调用,它会在err非nil时panic,一般用于变量初始化: ``` var t = template.Must(template.New("name").Parse("html")) ``` ### func [New](https://github.com/golang/go/blob/master/src/html/template/template.go#L215 "View Source") ``` func New(name string) *Template ``` 创建一个名为name的模板。 ### func [ParseFiles](https://github.com/golang/go/blob/master/src/html/template/template.go#L305 "View Source") ``` func ParseFiles(filenames ...string) (*Template, error) ``` ParseFiles函数创建一个模板并解析filenames指定的文件里的模板定义。返回的模板的名字是第一个文件的文件名(不含扩展名),内容为解析后的第一个文件的内容。至少要提供一个文件。如果发生错误,会停止解析并返回nil。 ### func [ParseGlob](https://github.com/golang/go/blob/master/src/html/template/template.go#L358 "View Source") ``` func ParseGlob(pattern string) (*Template, error) ``` ParseGlob创建一个模板并解析匹配pattern的文件(参见glob规则)里的模板定义。返回的模板的名字是第一个匹配的文件的文件名(不含扩展名),内容为解析后的第一个文件的内容。至少要存在一个匹配的文件。如果发生错误,会停止解析并返回nil。ParseGlob等价于使用匹配pattern的文件的列表为参数调用ParseFiles。 ### func (\*Template) [Name](https://github.com/golang/go/blob/master/src/html/template/template.go#L250 "View Source") ``` func (t *Template) Name() string ``` 返回模板t的名字。 ### func (\*Template) [Delims](https://github.com/golang/go/blob/master/src/html/template/template.go#L277 "View Source") ``` func (t *Template) Delims(left, right string) *Template ``` Delims方法用于设置action的分界字符串,应用于之后的Parse、ParseFiles、ParseGlob方法。嵌套模板定义会继承这种分界符设置。空字符串分界符表示相应的默认分界符:{{或}}。返回值就是t,以便进行链式调用。 ### func (\*Template) [Funcs](https://github.com/golang/go/blob/master/src/html/template/template.go#L267 "View Source") ``` func (t *Template) Funcs(funcMap FuncMap) *Template ``` Funcs方法向模板t的函数字典里加入参数funcMap内的键值对。如果funcMap某个键值对的值不是函数类型或者返回值不符合要求会panic。但是,可以对t函数列表的成员进行重写。方法返回t以便进行链式调用。 ### func (\*Template) [Clone](https://github.com/golang/go/blob/master/src/html/template/template.go#L179 "View Source") ``` func (t *Template) Clone() (*Template, error) ``` Clone方法返回模板的一个副本,包括所有相关联的模板。模板的底层表示树并未拷贝,而是拷贝了命名空间,因此拷贝调用Parse方法不会修改原模板的命名空间。Clone方法用于准备模板的公用部分,向拷贝中加入其他关联模板后再进行使用。 如果t已经执行过了,会返回错误。 ### func (\*Template) [Lookup](https://github.com/golang/go/blob/master/src/html/template/template.go#L284 "View Source") ``` func (t *Template) Lookup(name string) *Template ``` Lookup方法返回与t关联的名为name的模板,如果没有这个模板会返回nil。 ### func (\*Template) [Templates](https://github.com/golang/go/blob/master/src/html/template/template.go#L38 "View Source") ``` func (t *Template) Templates() []*Template ``` Templates方法返回与t相关联的模板的切片,包括t自己。 ### func (\*Template) [New](https://github.com/golang/go/blob/master/src/html/template/template.go#L231 "View Source") ``` func (t *Template) New(name string) *Template ``` New方法创建一个和t关联的名字为name的模板并返回它。这种可以传递的关联允许一个模板使用template action调用另一个模板。 ### func (\*Template) [AddParseTree](https://github.com/golang/go/blob/master/src/html/template/template.go#L151 "View Source") ``` func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) ``` AddParseTree方法使用name和tree创建一个模板并使它和t相关联。 如果t已经执行过了,会返回错误。 ### func (\*Template) [Parse](https://github.com/golang/go/blob/master/src/html/template/template.go#L120 "View Source") ``` func (t *Template) Parse(src string) (*Template, error) ``` Parse方法将字符串text解析为模板。嵌套定义的模板会关联到最顶层的t。Parse可以多次调用,但只有第一次调用可以包含空格、注释和模板定义之外的文本。如果后面的调用在解析后仍剩余文本会引发错误、返回nil且丢弃剩余文本;如果解析得到的模板已有相关联的同名模板,会覆盖掉原模板。 ### func (\*Template) [ParseFiles](https://github.com/golang/go/blob/master/src/html/template/template.go#L312 "View Source") ``` func (t *Template) ParseFiles(filenames ...string) (*Template, error) ``` ParseGlob方法解析filenames指定的文件里的模板定义并将解析结果与t关联。如果发生错误,会停止解析并返回nil,否则返回(t, nil)。至少要提供一个文件。 ### func (\*Template) [ParseGlob](https://github.com/golang/go/blob/master/src/html/template/template.go#L367 "View Source") ``` func (t *Template) ParseGlob(pattern string) (*Template, error) ``` ParseFiles方法解析匹配pattern的文件里的模板定义并将解析结果与t关联。如果发生错误,会停止解析并返回nil,否则返回(t, nil)。至少要存在一个匹配的文件。 ### func (\*Template) [Execute](https://github.com/golang/go/blob/master/src/html/template/template.go#L69 "View Source") ``` func (t *Template) Execute(wr io.Writer, data interface{}) error ``` Execute方法将解析好的模板应用到data上,并将输出写入wr。如果执行时出现错误,会停止执行,但有可能已经写入wr部分数据。模板可以安全的并发执行。 ### func (\*Template) [ExecuteTemplate](https://github.com/golang/go/blob/master/src/html/template/template.go#L82 "View Source") ``` func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error ``` ExecuteTemplate方法类似Execute,但是使用名为name的t关联的模板产生输出。 {% endraw %}