更多Go内容请见: https://blog.csdn.net/weixin_39777626/article/details/85066750
模板引擎
类型
- 无逻辑模板引擎:将模板中指定的占位符替换成相应的动态数据
- 嵌入逻辑模板引擎:执行代码,并进行相应的字符串替换工作
Go 模板引擎
语法分析——ParseFile()
执行模板——Execute()
工作原理
一个简单的模板
<! DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Go Web Programming</title>
</head>
<body>
{{.}}
</body>
</html>
在处理器函数中出发模板引擎
package main
import (
"html/template"
"net/http"
)
func process(w http.ResponseWriter, r *http.Request) {
t, _ := template.ParseFiles("tmpl.html")
t.Execute(w, "Hello World!")
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/process", process)
server.ListenAndServe()
}
动作
条件动作
在处理器中生成随机数
package main
import (
"html/template"
"math/rand"
"net/http"
"time"
)
func process(w http.ResponseWriter, r *http.Request) {
t, _ := template.ParseFiles("tmpl.html")
rand.Seed(time.Now().Unix())
t.Execute(w, rand.Intn(10) > 5)
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/process", process)
server.ListenAndServe()
}
tmpl.html 文件(使用了条件语句)
<! DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Go Web Programming</title>
</head>
<body>
{{if .}}
Number is greater than 5 !
{{else}}
Number is 5 or less !
{{end}}
</body>
</html>
迭代动作
调用迭代动作
package main
import (
"html/template"
"net/http"
)
func process(w http.ResponseWriter, r *http.Request) {
t, _ := template.ParseFiles("tmpl.html")
days := []string{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}
t.Execute(w, days)
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/process", process)
server.ListenAndServe()
}
tmpl.html 文件(使用了迭代语句)
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Go Web Programming</title>
</head>
<body>
<ul>
{{range . }}
<li>{{ . }}</li>
{{end}}
</ul>
</body>
</html>
tmpl.html 文件(带有备选结果的迭代语句)
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Go Web Programming</title>
</head>
<body>
<ul>
{{range . }}
<li>{{ . }}</li>
{{else}}
<li>Nothing to show</li>
{{end}}
</ul>
</body>
</html>
设置动作
package main
import (
"html/template"
"net/http"
)
func process(w http.ResponseWriter, r *http.Request) {
t, _ := template.ParseFiles("tmpl.html")
t.Execute(w, "hello")
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/process", process)
server.ListenAndServe()
}
tmpl.html 文件(对点进行设置)
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Go Web Programming</title>
</head>
<body>
<div>The dot is {{ . }}</div>
<div>
{{with "world"}}
Now the dot is set to {{ . }}
{{end}}
</div>
<div>The dot is {{ . }} again</div>
</body>
</html>
tmpl.html 文件(在设置点的时候提供备选方案)
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Go Web Programming</title>
</head>
<body>
<div>The dot is {{ . }}</div>
<div>
{{with "world"}}
Now the dot is set to {{ . }}
{{else}}
The dot is still {{ . }}
{{end}}
</div>
<div>The dot is {{ . }} again</div>
</body>
</html>
包含动作
t1.html
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=9">
<title>Go Web Programming</title>
</head>
<body>
<div>This is t1.html before</div>
<div>This is the value of the dot in t1.html - [{{ . }}]</div>
<hr/>
{{template "t2.html"}}
<hr/>
<div>This is t1.html after</div>
</body>
</html>
t2.html
<div style="background-color : yellow ;">
This is t2.html<br/>
This is the value of the dot in t2.html - [{{ . }}]
</div>
调用嵌套模块
package main
import (
"html/template"
"net/http"
)
func process(w http.ResponseWriter, r *http.Request) {
t, _ := template.ParseFiles("t1.html", "t2.html")
t.Execute(w, "hello world")
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/process", process)
server.ListenAndServe()
}
t1.html (将 t1.html 中的数据传递给 t2.html )
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=9">
<title>Go Web Programming</title>
</head>
<body>
<div>This is t1.html before</div>
<div>This is the value of the dot in t1.html - [{{ . }}]</div>
<hr/>
{{template "t2.html" . }}
<hr/>
<div>This is t1.html after</div>
</body>
</html>
参数、变量和管道
函数
模板引擎函数 | 输入 | 多个参数 |
返回 | 一个值 | |
一个值和一个错误 |
创建自定义模板函数
package main
import (
"html/template"
"net/http"
"time"
)
func formatDate(t time.Time) string {
layout := "2006-01-02"
return t.Format(layout)
}
func process(w http.ResponseWriter, r *http.Request) {
funcMap := template.FuncMap{"fdate": formatDate}
t := template.New("tmpl.html").Funcs(funcMap)
t, _ = t.ParseFiles("tmpl.html")
t.Execute(w, time.Now())
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/process", process)
server.ListenAndServe()
}
tmpl.html(通过管道使用自定义函数)
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Go Web Programming</title>
</head>
<body>
<div>The date/time is {{ . | fdate }}</div>
</body>
</html>
tmpl.html(通过传递参数使用自定义函数)
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Go Web Programming</title>
</head>
<body>
<div>The date/time is {{ fdate . }}</div>
</body>
</html>
上下文感知
定义: 可以根据内容所处的上下文改变其显示的内容
用途:
- 对被显示的内容实施正确的转义
- 实现自动的防御编程
展示模板上下文感知
package main
import (
"html/template"
"net/http"
)
func process(w http.ResponseWriter, r *http.Request) {
t, _ := template.ParseFiles("tmpl.html")
content := `I asked:<i>"What's up?"</i>`
t.Execute(w, content)
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/process", process)
server.ListenAndServe()
}
tmpl.html(上下文感知模板)
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Go Web Programming</title>
</head>
<body>
<div>{{ . }}</div>
<div><a href="/{{ . }}">Path</a></div>
<div><a href="/?q={{ . }}">Query</a></div>
<div><a onclick="f('{{ . }}')">Onclick</a></div>
</body>
</html>
防御XSS攻击
持久性XSS漏洞(XSS攻击方式):服务器将攻击者存储的数据原原本本地显示给其他用户
form.html(实施XSS攻击的表单)
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Go Web Programming</title>
</head>
<body>
<form action="/process" method="post">
Comment:<input name="comment" type="text">
<hr/>
<button id="submit">Submit</button>
</form>
</body>
</html>
测试XSS攻击
package main
import (
"html/template"
"net/http"
)
func process(w http.ResponseWriter, r *http.Request) {
t, _ := template.ParseFiles("tmpl.html")
t.Execute(w, r.FormValue("comment"))
}
func form(w http.ResponseWriter, r *http.Request) {
t, _ := template.ParseFiles("form.html")
t.Execute(w, nil)
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/process", process)
http.HandleFunc("/form", form)
server.ListenAndServe()
}
tmpl.html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Go Web Programming</title>
</head>
<body>
<div>{{ . }}</div>
</body>
</html>
<script>alert('Pwnd!');</script>
不对HTML进行转义
FireFox
package main
import (
"html/template"
"net/http"
)
func process(w http.ResponseWriter, r *http.Request) {
t, _ := template.ParseFiles("tmpl.html")
t.Execute(w, template.HTML(r.FormValue("comment")))
}
func form(w http.ResponseWriter, r *http.Request) {
t, _ := template.ParseFiles("form.html")
t.Execute(w, nil)
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/process", process)
http.HandleFunc("/form", form)
server.ListenAndServe()
}
关闭内置XSS防御功能(IE,Chrome,Safari)
package main
import (
"html/template"
"net/http"
)
func process(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-XSS-Protection", "0")
t, _ := template.ParseFiles("tmpl.html")
t.Execute(w, template.HTML(r.FormValue("comment")))
}
func form(w http.ResponseWriter, r *http.Request) {
t, _ := template.ParseFiles("form.html")
t.Execute(w, nil)
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/process", process)
http.HandleFunc("/form", form)
server.ListenAndServe()
}
嵌套模板
布局:可以重复在多个页面上的固定模式
显示地定义一个模板
{{ define "layout" }}
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Go Web Programming</title>
</head>
<body>
{{ template "content" }}
</body>
</html>
{{ end }}
layout.html(在一个模板文件中定义多个模板)
{{ define "layout" }}
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Go Web Programming</title>
</head>
<body>
{{ template "content" }}
</body>
</html>
{{ end }}
{{ define "content" }}
Hello World !
{{ end }}
使用显式定义的模板
package main
import (
"html/template"
"net/http"
)
func process(w http.ResponseWriter, r *http.Request) {
t, _ := template.ParseFiles("layout.html")
t.ExecuteTemplate(w, "layout", "")
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/process", process)
server.ListenAndServe()
}
red_hello.html
{{ define "content" }}
<h1 style="color:red;">Hello World!</h1>
{{ end }}
blue_hello.html
{{ define "content" }}
<h1 style="color:blue;">Hello World!</h1>
{{ end }}
不同模板中定义的同名模板
package main
import (
"html/template"
"math/rand"
"net/http"
"time"
)
func process(w http.ResponseWriter, r *http.Request) {
rand.Seed(time.Now().Unix())
var t *template.Template
if rand.Intn(10) > 5 {
t, _ = template.ParseFiles("layout.html", "red_hello.html")
} else {
t, _ = template.ParseFiles("layout.html", "blue_hello.html")
}
t.ExecuteTemplate(w, "layout", "")
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/process", process)
server.ListenAndServe()
}
通过块动作定义默认模板
块动作:允许用户定义一个模板并且立即使用
只对layout.html进行语法分析
package main
import (
"html/template"
"math/rand"
"net/http"
"time"
)
func process(w http.ResponseWriter, r *http.Request) {
rand.Seed(time.Now().Unix())
var t *template.Template
if rand.Intn(10) > 5 {
t, _ = template.ParseFiles("layout.html", "red_hello.html")
} else {
t, _ = template.ParseFiles("layout.html")
}
t.ExecuteTemplate(w, "layout", "")
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/process", process)
server.ListenAndServe()
}
layout.html(通过块动作添加默认的content模板)
{{ define "layout" }}
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Go Web Programming</title>
</head>
<body>
{{ block "content" . }}
<h1 style="color:blue;">Hello World!</h1>
{{ end }}
</body>
</html>
更多Go内容请见: https://blog.csdn.net/weixin_39777626/article/details/85066750