ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Go 模板初识

Go 模板初识 个人主页会编程的土豆欢迎来访作者简介后端学习者❄️个人专栏数据结构与算法数据库leetcode✨那些你一个人走过的夜路终将化作照亮未来的光目标搞清楚模板是什么、标准库怎么解析与执行、text/template和html/template的区别并能写出第一个可运行的渲染示例。1. 为什么需要模板做 Web 或生成报告时经常要把动态数据填进一段相对固定的文本里。如果不使用模板很容易写成这样html : h1Hello, user.Name /h1 html p年龄 strconv.Itoa(user.Age) /p问题很明显难维护HTML 结构和 Go 代码缠在一起易出错引号、转义、换行一多就乱不安全用户输入直接拼进 HTML可能造成 XSS难复用页头页脚无法干净地拆分复用模板引擎的思路是视图模板文件和数据Go 里的 struct/map分离模板文件长什么样 数据填什么 → 最终输出HTML/文本Go 标准库提供了两套模板引擎语法几乎相同包用途text/template纯文本邮件正文、配置、代码生成等html/templateHTML自动按上下文转义降低 XSS 风险做网页时优先用html/template2. 模板长什么样最简单的 HTML 模板!-- hello.html -- !DOCTYPE html html head meta charsetutf-8 title问候/title /head body h1Hello, {{.Name}}!/h1 p你今年 {{.Age}} 岁。/p /body /html关键点是双花括号{{ }}{{.Name}}输出当前数据的Name字段这里的.叫当前上下文dot一开始等于你传入Execute的那份数据模板里普通文字原样输出只有{{ }}里的内容由引擎计算3. 三个核心步骤Parse → 准备数据 → Execute用一句话概括标准库用法Parse把模板文本解析成内存中的模板对象准备数据构造 struct / map / 基本类型Execute把数据灌进模板写出结果3.1 完整最小示例输出到终端package main import ( html/template os ) type User struct { Name string Age int } func main() { const tpl Hello, {{.Name}}! Age{{.Age}} t, err : template.New(hello).Parse(tpl) if err ! nil { panic(err) } u : User{Name: 七米, Age: 18} if err : t.Execute(os.Stdout, u); err ! nil { panic(err) } }运行结果Hello, 七米! Age18逐步说明template.New(hello)创建一个名为hello的模板.Parse(tpl)解析字符串模板Execute(os.Stdout, u)以u为根数据.结果写到标准输出3.2 从文件解析更贴近真实项目package main import ( html/template net/http ) type User struct { Name string Age int } func main() { http.HandleFunc(/, func(w http.ResponseWriter, r *http.Request) { tmpl, err : template.ParseFiles(hello.html) if err ! nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } data : User{Name: 七米, Age: 18} if err : tmpl.Execute(w, data); err ! nil { http.Error(w, err.Error(), http.StatusInternalServerError) } }) http.ListenAndServe(:8080, nil) }浏览器访问http://localhost:8080就会看到渲染后的页面说明ParseFiles从磁盘读模板Execute(w, data)w是http.ResponseWriter实现了io.Writer所以可以直接当输出目标生产环境通常不会每次请求都ParseFiles后面会讲缓存/Must/一次加载入门先求正确4.template.Must启动期失败就直接崩解析模板失败时很多程序选择「进程直接退出」避免带着坏模板跑服务tmpl : template.Must(template.ParseFiles(hello.html))Must的逻辑等价于t, err : template.ParseFiles(hello.html) if err ! nil { panic(err) }适合在main或包初始化时加载模板不适合在每个请求里乱用panic 会打挂 goroutine/进程。5. 数据可以是什么模板的根数据常见有三类。5.1 结构体最常用type PageData struct { Title string User User }模板title{{.Title}}/title p{{.User.Name}}/p字段必须导出首字母大写否则模板访问不到。5.2 mapdata : map[string]any{ Title: 首页, Name: 七米, }模板title{{.Title}}/title p{{.Name}}/pGin 里的gin.H本质上就是map[string]any后面 lesson09 会用到。5.3 基本类型tmpl.Execute(w, 世界)模板Hello, {{.}}!此时.本身就是字符串世界。6.text/templatevshtml/template语法几乎一样差别在输出是否做 HTML 安全处理。对比实验假设用户名是恶意输入name : scriptalert(xss)/script用text/template会原样输出脚本标签浏览器可能执行 JS危险。用html/template会转义成类似lt;scriptgt;alert(#34;xss#34;)lt;/scriptgt;页面上显示的是文本而不是可执行脚本。怎么选场景选择返回 HTML 页面html/template生成纯文本邮件、SQL 片段以外的文本、代码text/template不确定Web 相关一律html七米课里讲 Web后续基本围绕html/template。7.Parse家族 API 速览入门阶段先熟悉这几个// 1) 字符串 template.New(name).Parse(Hello {{.Name}}) // 2) 一个或多个文件 template.ParseFiles(a.html, b.html) // 3) 按 glob 匹配 template.ParseGlob(templates/*.html)注意ParseFiles/ParseGlob返回的是一个模板集合*template.Template集合里可以有多个命名模板单文件时Execute通常就能工作多文件时更推荐ExecuteTemplatelesson06 会细讲Execute和ExecuteTemplatetmpl.Execute(w, data) // 执行「默认/主」模板 tmpl.ExecuteTemplate(w, home, data) // 按名字执行集合中的某个模板初学可以先记住只有一个简单文件Execute够用一旦出现{{define xxx}}或多个页面用ExecuteTemplate8. 一个稍完整的入门例子目录lesson04-demo/ main.go hello.htmlhello.html!DOCTYPE html html langzh-CN head meta charsetutf-8 title{{.Title}}/title style body { font-family: sans-serif; max-width: 640px; margin: 40px auto; } .card { border: 1px solid #ddd; padding: 16px; border-radius: 8px; } /style /head body h1{{.Title}}/h1 div classcard p用户{{.User.Name}}/p p年龄{{.User.Age}}/p /div /body /htmlmain.gopackage main import ( html/template log net/http ) type User struct { Name string Age int } type ViewData struct { Title string User User } func main() { tmpl : template.Must(template.ParseFiles(hello.html)) http.HandleFunc(/, func(w http.ResponseWriter, r *http.Request) { data : ViewData{ Title: 模板初识 Demo, User: User{Name: 七米, Age: 18}, } if err : tmpl.Execute(w, data); err ! nil { log.Println(execute:, err) } }) log.Println(listening on :8080) log.Fatal(http.ListenAndServe(:8080, nil)) }运行go run .打开浏览器看效果。把User.Name改成带script的字符串观察html/template的转义行为——这是初识阶段很值得做的小实验。9. 常见新手坑lesson04 就会碰到坑 1字段不大写type User struct { name string // 错模板访问不到 }模板{{.name}}会失败或为空严格模式下报错。应写成Name。坑 2文件路径不对ParseFiles(hello.html)相对的是进程工作目录不是源码文件所在目录。在别的目录执行go run时容易找不到文件。坑 3忽略 errorParse/Execute都可能失败。至少要打日志或返回 500否则页面空白却不知道原因。坑 4用text/template渲 HTML能跑但不安全。Web 场景请用html/template。坑 5每次请求都 Parse性能入门可以接受真正服务应在启动时解析一次并复用*template.Template它是并发安全可复用的。模板描述形状数据提供内容用html/template解析后Execute出去。
返回列表