Go html/template 怎么安全把后端数据交给前端:别把 JSON 硬塞进 template.JS
做 Go 服务端渲染时,首屏经常要把用户信息、功能开关和分页条件交给一小段前端脚本。数据里一旦出现引号、换行或尖括号,很多人会先 json.Marshal,再把结果转成 template.JS 塞进页面。页面看起来立刻正常了,但这一步也绕开了 html/template 原本替你做的上下文转义。
要点速览
- 把 Go 结构体直接放在普通
的 JavaScript 值位置,html/template会按上下文生成可用的 JSON。 - 不要把来自请求、数据库或第三方接口的 JSON 仅靠转为
template.JS标记成安全内容。 - 页面只需要一个短字段时,
data-user-id这类属性比塞一整段初始化对象更直观。 - 回归时要带上引号、
片段和 Unicode 字符,确认页面没有长出额外标签或截断脚本。
问题不在 JSON,而在它被放进了哪个上下文
先看一个常见场景:服务端想让浏览器拿到当前用户和实验开关,于是在模板里写 const pageData = {{ .Page }};。这不是简单的字符串替换。html/template 会识别当前动作位于 JavaScript 上下文;传入的是结构体或 map 时,它会生成适合该位置的 JSON。这个能力的前提是模板由可信开发者编写,而渲染数据可以是不可信的。
真正危险的捷径是把一段外部 JSON 直接包装成 template.JS。这个类型表示“已知安全的 JavaScript 表达式”,责任随之落到调用方。官方文档明确提醒:即便 JSON 在语法上有效,只要数据不可信,就不该因为它像 JSON 而跳过模板的处理。
最小配方:让结构体进入 script 的值位置
先不要手工拼引号,也不用预先把对象编码成字符串。给视图模型一个清晰的边界,再把它直接交给模板。下面是模板片段与数据类型;项目里的渲染入口照常把 Page 作为数据的一部分传入即可。
package view
import "html/template"
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
type PageData struct {
User User `json:"user"`
Flags []string `json:"flags"`
}
type PageModel struct {
Page PageData
}
const pageHTML = `
`
func parsePage() (*template.Template, error) {
return template.New("profile").Parse(pageHTML)
}
关键是 {{ .Page }} 前后没有再包一层手写引号。PageData 不是普通文本,它在脚本值位置被模板按 JavaScript 规则处理。先在本地用用户名 Li "A"、 和包含换行的备注走一遍页面:浏览器应该拿到同一个数据值,但 DOM 中不能多出一段意外的标签或脚本。

前端读取时,把初始化对象当数据而不是模板碎片
有了 pageData,前端代码就按普通对象读取。这个阶段最容易被忽略的细节是:把数据用于 textContent、属性赋值或受控的组件状态,而不是拿字符串再拼一段 HTML。这样前后端的责任也更清楚——Go 负责输出结构化初始数据,浏览器代码负责按 DOM API 渲染。
const badge = document.querySelector("#profile");
if (pageData.flags.includes("beta")) {
badge.dataset.mode = "beta";
}
badge.textContent = `${pageData.user.name} #${pageData.user.id}`;
这一步可以顺手做一个核对:打开浏览器开发者工具,确认 pageData 是对象而不是一串双重编码的 JSON 字符串;再确认页面显示的是原始文字,不是 " 一类转义残留。若拿到的是字符串,通常是某层又做了一次 json.Marshal,而不是模板失效。
只传一个短字段时,data-* 往往更省心
并非每个页面都需要一个初始化对象。比如一个“编辑资料”按钮只要当前用户 ID,直接写到 data-user-id 更容易审查,也不必让页面多一段脚本数据。属性值仍由 html/template 处理,前端用 dataset 读取即可。
这里的边界很实际:少量标量放属性没问题;筛选器、权限集合、嵌套对象或上百条列表,不适合拆成一堆 data-*。数据开始变复杂时,回到上面的结构体配方,或者通过一个受认证的 JSON 接口按需加载。

template.JS 不是给 JSON 开的绿色通道
template.JS 仍有合理用途,例如模板作者自己写死的一小段 JavaScript 表达式,并且能证明内容不含外部输入。它不是“JSON 字符串专用类型”,更不是给数据库字段、查询参数、CMS 内容或上游接口返回值消除转义的工具。
如果上游给的是 JSON 文本,先用 json.Unmarshal 解析成 Go 结构体或 map,再把该对象传给模板。解析失败就把它当作数据错误处理,而不是为了让页面先出来而原样塞进脚本。这个取舍看似多一步,却让类型、错误和安全边界都留在服务端。
上线前用四个输入检查渲染结果
模板安全问题往往不会在普通中文用户名上暴露。给页面准备四组固定样本,检查响应源码和浏览器显示,比只看“页面能打开”可靠得多:
- 普通值:
Lin,确认对象字段和页面文字都正常。 - 引号值:
Lin "A",确认脚本没有提前结束,JavaScript 仍能读取对象。 - 标签样本:包含
或的文本,确认浏览器没有新增可运行标签。 - Unicode 与换行:确认中文、emoji 和多行备注不会变成双重编码字符串。
同时别忘了确认服务使用的是 html/template 而不是 text/template。两者 API 很像,但只有前者会针对 HTML、JavaScript、CSS 和 URL 上下文处理输出。升级 Go 版本时,也应把这组样本放进回归测试,尤其是项目有大量 script 模板片段时。
相关问题
能把 JSON 放进 type="application/json" 的 script 标签吗?
可以作为另一种页面数据载体,但要先验证所用 Go 版本与模板写法的上下文处理结果。若只是把 Go 对象交给页面的 JavaScript,普通 script 的值位置配合 {{ .Page }} 更直接,也更容易按官方文档理解。
data-* 能放一个完整 JSON 对象吗?
不建议作为默认方案。属性适合短字段;对象越大,转义、长度和调试成本越高。复杂数据用结构体进入 script 值位置,或通过 API 按需请求更清晰。
template.HTML 和 template.JS 的风险一样吗?
两者都是“已知安全内容”的显式标记,都会把审查责任交给调用方。只有内容确实由可信模板作者固定写死,且能证明不会混入外部数据时,才考虑使用。
为什么页面里的对象字段名不是我想要的小写?
为 Go 的结构体字段补上 json 标签,例如 json:"user"。这样模板在 JavaScript 上下文序列化时能得到稳定、便于前端读取的字段名。
把安全边界留在模板上下文里
服务端渲染页面并不排斥前端交互,关键是别把后端数据降成一段手工拼接的脚本文本。对象就按对象传给 html/template,短字段就用 data-*;只有真正可信的表达式才考虑 typed string。这样处理后,用户输入再复杂,模板上下文仍是那条最可靠的边界。
关于 JavaScript 上下文、typed string 和安全模型,可继续阅读 Go 官方的 html/template 文档 与 包说明源码。
Go 服务怎么用 Sec-Fetch-Site 拦住跨站请求:Fetch Metadata 的最小中间件
- 上一篇
- Go 服务怎么用 Sec-Fetch-Site 拦住跨站请求:Fetch Metadata 的最小中间件
- 下一篇
- Java JTable 双击怎么拿到正确行:MouseAdapter、排序转换和空白行判断
-
- Golang · Go教程 | 5小时前 | 并发 · Go教程 · trace.NewTask go tool trace Go runtime/trace 执行跟踪 trace.WithRegion
- Go runtime/trace 怎样按任务标记跟踪区间
- 391浏览 收藏
-
- Golang · Go教程 | 6小时前 | flag · go · Go 命令行参数 flag.TextVar encoding.TextUnmarshaler
- Go flag.TextVar 怎样把自定义类型接入命令行
- 184浏览 收藏
-
- Golang · Go教程 | 7小时前 | 错误处理 · 模板 · Go教程 · html/template · 模板渲染 Go html/template missingkey 模板缺失字段 Execute错误
- Go html/template 缺失字段的严格渲染配置与错误处理
- 371浏览 收藏
-
- Golang · Go教程 | 7小时前 | html · go · 模板 · url · Go html/template 自动转义 URL上下文 template.URL
- Go html/template 怎样避免 URL 上下文误用
- 326浏览 收藏
-
- Golang · Go教程 | 7小时前 |
- Go text/template.ParseFS 怎样加载嵌入文件模板
- 208浏览 收藏
-
- Golang · Go教程 | 7小时前 |
- Go database/sql.NamedArg 怎样给 SQL 参数命名
- 311浏览 收藏
-
- Golang · Go教程 | 8小时前 | HTTP · go · Gin · Gin ShouldBindBodyWith 请求体重复绑定 ShouldBind binding.JSON
- Gin ShouldBindBodyWith 怎么让同一个请求体绑定两次
- 134浏览 收藏
-
- Golang · Go教程 | 9小时前 | go · 文件系统 · Go os.ReadDir Go File.ReadDir Go DirEntry Go 目录遍历
- Go os.ReadDir 怎样高效读取目录条目
- 269浏览 收藏
-
- Golang · Go教程 | 9小时前 | go · Go go/types.Config Go Importer Go 类型检查 types.Check
- Go go/types.Config 怎样给类型检查接入导入器
- 222浏览 收藏
-
- Golang · Go教程 | 9小时前 |
- Go maphash.Hash 怎样用固定种子复现哈希结果
- 341浏览 收藏
-
- Golang · Go教程 | 9小时前 | Go 字节切片 encoding/binary AppendByteOrder
- Go binary.ByteOrder.Append 怎样把整数追加到现有字节切片
- 373浏览 收藏
-
- Golang · Go教程 | 9小时前 | go · IPv6 Go ipv4 netip.ParsePrefix CIDR
- Go netip.ParsePrefix 怎样解析 CIDR 字符串
- 334浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 566次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 609次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 639次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 597次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 417次使用
-
- Java 性能优化上线清单:从定位、改造到灰度发布
- 2026-06-11 860浏览
-
- Spring Boot 压测验证:Gatling、JMeter 与性能回归门禁
- 2026-06-11 843浏览
-
- Java NMT 非堆内存排查:Direct Buffer、线程栈与 Metaspace 分析
- 2026-06-11 826浏览
-
- Spring Boot 容器内存优化:JVM 堆、非堆与 MaxRAMPercentage
- 2026-06-11 809浏览
-
- Tomcat 连接与线程参数调优:maxThreads、acceptCount 与 KeepAlive
- 2026-06-11 792浏览

