首页 > 后端开发 > Golang > 正文

Go html/template:在 HTML 中安全地嵌入 JSON 数据

聖光之護
发布: 2025-10-27 12:08:01
原创
733人浏览过

Go html/template:在 HTML 中安全地嵌入 JSON 数据

本文探讨了在 go 的 `html/template` 包中,如何在不使用 `<script>` 标签的情况下,将 go 数据结构作为 <a style="color:#f60; text-decoration:underline;" title= "js"href="https://www.php.cn/zt/15802.html" target="_blank">json 字符串安全地嵌入到 html 内容中。我们将介绍两种主要方法:利用 `encoding/<a style="color:#f60; text-decoration:underline;" title= "json"href="https://www.php.cn/zt/15848.html" target="_blank">json` 进行数据序列化并结合 `template.html` 类型来阻止不必要的 html 转义,以及理解 `js` 上下文过滤器在 <a style="color:#f60; text-decoration:underline;" title= "javascript"href="https://www.php.cn/zt/15724.html" target="_blank">javascript 字面量转义中的作用及其与 json 序列化的<a style="color:#f60; text-decoration:underline;" title= "区别"href="https://www.php.cn/zt/27988.html" target="_blank">区别,确保输出内容的正确性和安全性。</script>

在现代 Web 开发中,我们经常需要将后端 Go 应用程序中的数据结构直接作为 JSON 格式嵌入到 HTML 页面中。这通常用于初始化 JavaScript 库(例如 X-Editable 的 source 属性)、填充 data-* 属性,或在不使用 AJAX 的情况下向前端传递配置信息。html/template 包在处理输出时,默认会进行 HTML 转义以防止跨站脚本攻击 (XSS)。然而,当我们需要输出原始的 JSON 字符串时,这种默认行为会把 " 转换为 "、[ 转换为 [ 等,导致输出不再是有效的 JSON。

本教程将详细介绍两种实现这一目标的方法,并明确它们各自的适用场景和注意事项。

方法一:使用 encoding/json 和 template.HTML 实现真正的 JSON 输出

当目标是生成一个有效的 JSON 字符串,并将其直接嵌入到 HTML 元素(例如作为 data-* 属性的值,或在非 <script> 标签的文本内容中)时,这是最推荐且最安全的方法。

原理说明

  1. JSON 序列化:首先,在 Go 代码中,使用标准库 encoding/json 将 Go 数据结构序列化为 JSON 格式的字节数组或字符串。
  2. 标记为安全 HTML:然后,将生成的 JSON 字符串包装到 template.HTML 类型中。html/template 包在遇到 template.HTML 类型的数据时,会认为这段内容是“安全”的,因此不会对其进行额外的 HTML 转义。

示例代码

package main

import (
    "encoding/json"
    "html/template"
    "log"
    "os"
)

func main() {
    // 定义一个示例数据结构
    type KeyValue struct {
        A, B string
    }

    // 创建一个数据切片
    data := []KeyValue{{"foo", "bar"}, {"bar", "baz"}}

    // 步骤 1: 使用 encoding/json 将 Go 数据结构序列化为 JSON 字符串
    // MarshalIndent 可以生成格式化的 JSON,方便阅读;Marshal 则生成紧凑的 JSON。
    jsonBytes, err := json.MarshalIndent(data, "", " ")
    if err != nil {
        log.Fatalf("JSON 序列化失败: %v", err)
    }
    jsonString := string(jsonBytes)

    // 步骤 2: 将 JSON 字符串包装成 template.HTML 类型
    // 这会告诉 html/template,该字符串是安全的 HTML,不需要进行转义。
    safeJSON := template.HTML(jsonString)

    // 定义模板,直接输出数据
    // 注意:这里的 {{.}} 将直接输出 safeJSON 的内容,不会再进行 HTML 转义。
    tmpl, err := template.New("jsonOutput").Parse(`<html><body>Hello <div id="data" data-json='{{.}}'></div></body></html>` + "\n")
    if err != nil {
        log.Fatal(err)
    }

    // 执行模板
    log.Println("--- 使用 template.HTML 输出 JSON ---")
    err = tmpl.Execute(os.Stdout, safeJSON)
    if err != nil {
        log.Fatal(err)
    }

    // 另一个示例:直接在 body 中输出
    tmplBody, err := template.New("jsonBody").Parse(`<html><body>Hello {{.}}</body></html>` + "\n")
    if err != nil {
        log.Fatal(err)
    }
    log.Println("\n--- 直接在 body 中输出 JSON ---")
    err = tmplBody.Execute(os.Stdout, safeJSON)
    if err != nil {
        log.Fatal(err)
    }
}
登录后复制

输出结果

--- 使用 template.HTML 输出 JSON ---
<html><body>Hello <div id="data" data-json='[
 {
  "A": "foo",
  "B": "bar"
 },
 {
  "A": "bar",
  "B": "baz"
 }
]'></div></body></html>

--- 直接在 body 中输出 JSON ---
<html><body>Hello [
 {
  "A": "foo",
  "B": "bar"
 },
 {
  "A": "bar",
  "B": "baz"
 }
]</body></html>
登录后复制

从输出可以看出,JSON 字符串被完整且正确地嵌入到了 HTML 中,没有经过任何 HTML 转义。这正是我们所期望的,例如,可以用于 data-json 属性或直接作为页面内容。

立即学习前端免费学习笔记(深入)”;

注意事项

  • 安全性:只有当您确定 JSON 字符串的内容是可信的,或者它已经通过 encoding/json 正确序列化(该库本身会处理字符串中的特殊字符转义,例如 " 会被转义为 \"),才应该使用 template.HTML。如果将不可信的原始用户输入直接包装成 template.HTML,将可能导致 XSS 漏洞。
  • 属性值转义:当 JSON 字符串作为 HTML 属性值时(如 data-json='...'),如果 JSON 字符串内部包含单引号 ',可能会导致属性值提前结束。通常情况下,encoding/json 会将内部的 ' 转义为 \u0027," 转义为 \",这在大多数情况下是安全的。如果属性值使用双引号 " 包裹,则 JSON 字符串内部的 " 需被 \" 转义,而 html/template 在 {{.}} 输出到属性上下文时,会进一步处理 " 为 "。为了避免复杂性,推荐在 HTML 属性中使用单引号包裹属性值,并确保 JSON 字符串内部不包含裸露的单引号。json.Marshal 产生的 JSON 字符串通常只包含双引号,所以使用单引号包裹属性值是安全的。

方法二:理解 js 上下文过滤器(JavaScript 字面量转义)

html/template 包提供了一个内置的 js 上下文过滤器,其作用是将值转义,使其可以安全地作为 JavaScript 字面量嵌入到 JavaScript 代码中。然而,它并不会将 Go 数据结构序列化为 JSON 字符串

功能说明

{{js .}} 的主要目的是确保 Go 变量的值在 JavaScript 代码中作为字符串、数字或布尔值字面量使用时不会破坏 JavaScript 语法或引入 XSS 漏洞。例如,如果 Go 变量是一个字符串 alert('XSS'),在 {{js .}} 处理后可能会变成 'alert(\'XSS\')',可以安全地嵌入到 JavaScript 变量赋值中。

示例代码及输出分析

package main

import (
    "html/template"
    "log"
    "os"
)

func main() {
    type KeyValue struct {
        A, B string
    }

    data := []KeyValue{{"foo", "bar"}, {"bar", "baz"}}

    // 定义模板,使用 {{js .}}
    // 注意:这里的 {{js .}} 会对 data 进行 JavaScript 字面量转义,但不会进行 JSON 序列化。
    tmplJS, err := template.New("jsOutput").Parse("<html><body>Hello {{js .}}</body></html>\n")
    if err != nil {
        log.Fatal(err)
    }

    // 执行模板
    log.Println("--- 使用 {{js .}} 输出 ---")
    err = tmplJS.Execute(os.Stdout, data)
    if err != nil {
        log.Fatal(err)
    }
}
登录后复制

输出结果

--- 使用 {{js .}} 输出 ---
<html><body>Hello [{foo bar} {bar baz}]</body></html>
登录后复制

与 JSON 序列化的区别

从输出可以看出,{{js .}} 并没有将 data 切片转换为标准的 JSON 格式,例如 "A": "foo"。它只是输出了 Go 结构体的默认字符串表示,并确保其中的特殊字符(如引号、斜杠等)被正确转义,以便在 JavaScript 环境中安全使用。对于 Go 结构体或切片,其默认的字符串表示通常是 {字段名: 字段值} 的形式。

Find JSON Path Online
Find JSON Path Online

Easily find JSON paths within JSON objects using our intuitive Json Path Finder

Find JSON Path Online30
查看详情 Find JSON Path Online

因此,{{js .}} 不适用于在 HTML 中生成有效的 JSON 字符串。 如果您需要的是符合 JSON 规范的数据,以便被 JavaScript 解析器或库正确识别,请务必使用方法一。

总结与最佳实践

在 Go 的 html/template 中嵌入 JSON 数据时,选择正确的方法至关重要:

  1. 当您需要一个标准的、可被 JavaScript 解析器识别的 JSON 字符串时

    • 最佳实践:始终使用 encoding/json.Marshal(或 MarshalIndent)将 Go 数据结构序列化为 JSON 字符串。
    • 然后,将结果包装成 template.HTML 类型,以防止 html/template 对其进行不必要的 HTML 转义。
    • 示例:template.HTML(string(json.Marshal(myData)))
    • 适用场景:data-* 属性、初始化 JavaScript 库的配置对象、内联 JSON 数据块等。
  2. 当您需要在 <script> 标签内安全地嵌入一个 Go 变量作为 JavaScript 字面量时

    • 适用场景:将一个简单的 Go 字符串或数字直接赋值给 JavaScript 变量。
    • 使用 {{js .}} 上下文过滤器。
    • 重要提示:{{js .}} 不会将 Go 数据结构序列化为 JSON。它只负责转义,使其在 JavaScript 语法中安全。

通过理解这两种方法的区别和适用场景,您可以确保在 Go 应用程序中安全、高效地将数据以 JSON 格式嵌入到 HTML 页面中,同时避免潜在的安全漏洞和数据格式错误。

以上就是Go html/template:在 HTML 中安全地嵌入 JSON 数据的详细内容,更多请关注php中文网其它相关文章!

HTML速学教程(入门课程)
HTML速学教程(入门课程)

HTML怎么学习?HTML怎么入门?HTML在哪学?HTML怎么学才快?不用担心,这里为大家提供了HTML速学教程(入门课程),有需要的小伙伴保存下载就能学习啦!

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号