0

0

Go HTML 模板:安全渲染原始HTML内容而不被转义

碧海醫心

碧海醫心

发布时间:2025-09-30 13:59:25

|

305人浏览过

|

来源于php中文网

原创

Go HTML 模板:安全渲染原始HTML内容而不被转义

Go语言的html/template包默认会对管道中的HTML内容进行转义,以防止跨站脚本(XSS)攻击。若需在模板中插入原始、未转义的HTML,应将对应的数据字段类型明确声明为template.HTML。这样,模板引擎会将其视为安全HTML,直接渲染到输出中,从而避免不必要的转义。

Go HTML 模板的默认转义行为

html/template 包是 go 语言标准库中用于生成 html 输出的强大工具。为了增强安全性,它默认会对所有通过管道(pipeline)插入到 html 模板中的数据进行自动转义。这意味着,如果你的数据中包含 、&、" 等 html 特殊字符,它们会被转换为对应的 html 实体(例如,

然而,在某些场景下,我们可能需要渲染已经确定是安全的、包含原始 HTML 标记的内容。例如,从可信源获取的富文本内容,或者由后端生成的已知安全片段。在默认的转义机制下,这些原始 HTML 会被错误地转义,导致在浏览器中显示为纯文本而非预期的 HTML 结构。

考虑以下 Go 代码和 HTML 模板示例,它从 RSS 源获取新闻描述并尝试在网页上显示:

Go 代码片段(main.go):

package main

import (
    "fmt"
    "html/template"
    "log"
    "net/http"
)

// Item 结构体,Description 字段目前是 string 类型
type Item struct {
    Title       string
    Link        string
    Description string // 假设此字段可能包含原始HTML
}

func handler(w http.ResponseWriter, r *http.Request) {
    // 模拟从RSS源获取的数据
    data := struct {
        ItemList []Item
    }{
        ItemList: []Item{
            {
                Title: "Go Template Example",
                Link:  "http://example.com",
                // 这是一个包含原始HTML的Description字段
                Description: "

This is a rich text description with HTML tags.

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

", }, { Title: "Another Article", Link: "http://another.com", Description: "Regular text description.", }, }, } tmpl, err := template.ParseFiles("index.html") if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if err := tmpl.Execute(w, data); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } func main() { http.HandleFunc("/", handler) fmt.Println("Server listening on :8080") log.Fatal(http.ListenAndServe(":8080", nil)) }

HTML 模板文件(index.html):




    News Feed


    

Latest News

{{range .ItemList}}

{{.Title}}

{{.Description}}

{{end}}

当运行上述代码时,Description 字段中的原始 HTML 标记(如

, , )会被转义,导致浏览器渲染时显示为字面量字符串,而不是格式化的 HTML。例如,

This is a rich text description...

会在页面上显示为 zuojiankuohaophpcnpyoujiankuohaophpcnThis is a zuojiankuohaophpcnbyoujiankuohaophpcnrich textzuojiankuohaophpcn/byoujiankuohaophpcn description...zuojiankuohaophpcn/pyoujiankuohaophpcn。

解决方案:使用 template.HTML 类型

为了指示 html/template 包某个字符串是安全的,不应被转义,我们需要将其类型明确声明为 template.HTML。template.HTML 是 html/template 包提供的一个特殊类型,它告诉模板引擎该字符串内容已经被验证为安全,可以直接插入到 HTML 输出中。

要解决上述问题,只需修改 Go 结构体中包含原始 HTML 的字段类型:

ONLYOFFICE
ONLYOFFICE

用ONLYOFFICE管理你的网络私人办公室

下载
  1. 修改结构体字段类型: 将 Item 结构体中的 Description 字段从 string 类型更改为 template.HTML。

    // Item 结构体,Description 字段现在是 template.HTML 类型
    type Item struct {
        Title       string
        Link        string
        Description template.HTML // 将类型改为 template.HTML
    }
  2. 创建 template.HTML 实例: 在 Go 代码中为 Description 字段赋值时,需要将字符串显式转换为 template.HTML 类型。

    data := struct {
        ItemList []Item
    }{
        ItemList: []Item{
            {
                Title: "Go Template Example",
                Link:  "http://example.com",
                // 将字符串转换为 template.HTML
                Description: template.HTML("

    This is a rich text description with HTML tags.

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

    "), }, { Title: "Another Article", Link: "http://another.com", Description: template.HTML("Regular text description."), // 即使是纯文本,也可以使用 }, }, }

注意: HTML 模板文件 (index.html) 无需进行任何修改。模板引擎会根据传入的数据类型自动识别 template.HTML 并进行相应的处理。

完整示例

以下是修改后的完整 Go 代码和 HTML 模板,展示了如何正确地在 Go HTML 模板中渲染原始 HTML 内容。

Go 代码(main.go):

package main

import (
    "fmt"
    "html/template" // 导入 html/template 包
    "log"
    "net/http"
    "io/ioutil"
    "encoding/xml" // 用于解析RSS数据
)

// RSS 结构体,匹配RSS XML的根元素
type RSS struct {
    XMLName xml.Name `xml:"rss"`
    Items   Channel  `xml:"channel"`
}

// Channel 结构体,匹配RSS XML的channel元素
type Channel struct {
    XMLName  xml.Name `xml:"channel"`
    ItemList []Item   `xml:"item"`
}

// Item 结构体,包含新闻条目的信息
type Item struct {
    Title       string        `xml:"title"`
    Link        string        `xml:"link"`
    Description template.HTML `xml:"description"` // 关键修改:使用 template.HTML
}

func main() {
    // 模拟从Google News RSS获取数据
    res, err := http.Get("http://news.google.com/news?hl=en&gl=us&q=samsung&um=1&ie=UTF-8&output=rss")
    if err != nil {
        log.Fatalf("Failed to fetch RSS: %v", err)
    }
    defer res.Body.Close()

    asText, err := ioutil.ReadAll(res.Body)
    if err != nil {
        log.Fatalf("Failed to read RSS body: %v", err)
    }

    var rssData RSS
    err = xml.Unmarshal(asText, &rssData)
    if err != nil {
        log.Fatalf("Failed to unmarshal RSS: %v", err)
    }

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        handler(w, r, rssData.Items)
    })
    fmt.Println("Server listening on :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

func handler(w http.ResponseWriter, r *http.Request, channelData Channel) {
    tmpl, err := template.ParseFiles("index.html")
    if err != nil {
        http.Error(w, fmt.Sprintf("Error parsing template: %v", err), http.StatusInternalServerError)
        return
    }

    if err := tmpl.Execute(w, channelData); err != nil {
        http.Error(w, fmt.Sprintf("Error executing template: %v", err), http.StatusInternalServerError)
    }
}

HTML 模板文件(index.html):




    RSS News Feed
    


    

Latest News from RSS

{{range .ItemList}}

{{.Title}}

{{/* Description 字段将作为原始HTML被渲染 */}}

{{.Description}}

{{end}}

现在,当运行此程序并在浏览器中访问 http://localhost:8080 时,Description 字段中的内容将作为原始 HTML 被渲染,而不再被转义。例如,如果 Description 包含表格或图片标签,它们将正常显示。

重要注意事项与最佳实践

  1. 安全性警示: 使用 template.HTML 意味着你信任该内容是安全的,不会引入恶意脚本。切勿直接将未经净化的用户输入赋值给 template.HTML 类型。如果内容来自用户,必须先经过严格的 HTML 净化库(如 bluemonday)处理,移除所有潜在的恶意标签和属性,然后再将其转换为 template.HTML。
  2. 其他安全类型: html/template 包还提供了其他类似的类型来处理特定上下文中的安全内容:
    • template.CSS: 用于 CSS 样式表内容。
    • template.JS: 用于 JavaScript 代码。
    • template.URL: 用于 URL 属性(如 href)。
    • template.Srcset: 用于 Go HTML 模板:安全渲染原始HTML内容而不被转义 标签的 srcset 属性。 正确使用这些类型可以确保在不同上下文中生成安全的输出。
  3. html/template 与 text/template: Go 语言还有另一个模板包 text/template。text/template 不执行任何内容转义,因为它被设计用于生成非 HTML 的文本输出。如果你确定不需要 HTML 转义,并且生成的是纯文本,可以使用 text/template。但在生成 HTML 内容时,始终推荐使用 html/template 以利用其内置的安全机制。

总结

在 Go 语言的 html/template 中,默认的 HTML 转义是出于安全考虑,旨在防止 XSS 攻击。然而,当需要渲染已知安全的原始 HTML 内容时,可以通过将对应的数据字段类型声明为 template.HTML 来绕过自动转义。这一机制提供了一种灵活且安全的方式来处理富文本内容,但开发者必须牢记 template.HTML 意味着对内容的信任,因此务必确保其来源的安全性,对用户输入进行严格净化。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
数据类型有哪几种
数据类型有哪几种

数据类型有整型、浮点型、字符型、字符串型、布尔型、数组、结构体和枚举等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

309

2023.10.31

php数据类型
php数据类型

本专题整合了php数据类型相关内容,阅读专题下面的文章了解更多详细内容。

222

2025.10.31

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

463

2023.08.02

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

298

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

212

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1502

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

624

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

633

2024.03.22

java入门学习合集
java入门学习合集

本专题整合了java入门学习指南、初学者项目实战、入门到精通等等内容,阅读专题下面的文章了解更多详细学习方法。

1

2026.01.29

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Sass 教程
Sass 教程

共14课时 | 0.8万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3.1万人学习

CSS教程
CSS教程

共754课时 | 24.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

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