使用 go 模板解析显示为纯文本的页面中的 HTML 代码

Parsing HTML code in page shown as plain text with go Template

我已经开始使用 Go 语言,现在正在尝试创建一个 HTML 页面。我对 Go 和 HTML.

中的编码都很陌生

在 Go 程序中,我试图将 HTML 页面 (div) 解析为主 html 页面 (index.html) 我正在尝试使用 Go 中的模板将此 div 添加到主 html 页面。

我尝试将数据解析到的 html 页面如下所示:

<html>
<head>
    <meta charset="utf-8">
    <title>SmartHomePi Status</title>
    <link rel="stylesheet" href="../static/css/style.css">
</head>
<body>
    <h1>HomeControl Connection Status</h1>
    <div id="wrapper" width="100%">
        {{.SonoffBasic}}
    </div>
</body>

{{.SonoffBasic}} 部分是我尝试添加 div 的部分。 我尝试添加的 div 看起来像这样:

<div id="sonoffbasicdevice">
    <span class="%connectiondotclass%"></span>
    <p id="title">%title%</p>
    <p id="tempandhum">%humstatus%</p>
    <p id="ipaddress">%ipaddress%</p>
    <p id="portnumber">%portnumber%</p>
</div>

所有带有 %xxx% 的值都在 go 中被解析以包含有用的信息,并且一切正确。

但现在我正在尝试使用 Go 中的模板一起解析这两个,这里似乎出了点问题。

我正在使用 Go 中的以下函数执行此操作:

func renderHomeKitTemplate(w http.ResponseWriter, tmpl string, items *WebPageHTMLItems) {
    err := templates.ExecuteTemplate(w, "index.html", items)
} 

其中变量项是一个如下所示的结构:

type WebPageHTMLItems struct{
    SonoffBasic  string
}

其中 SonoffBasic 字符串包含 div 以及所有填写的信息。

我运行程序可以看到网页,但是显示网页的时候,没有解析div,显示的是纯文本,我哪里做错了这里?

这是否是将数据解析到 HTML 文件中的正确方法。我之所以使用这种添加完整 div 的方式,是因为我可以有多个 "sonoffbasicdevice" 项目并且应该添加多个。

使用template.HTML

html/template 提供自动的、上下文相关的转义以防止代码注入:

HTML templates treat data values as plain text which should be encoded so they can be safely embedded in an HTML document. The escaping is contextual, so actions can appear within JavaScript, CSS, and URI contexts.

html/template 包中有一个特殊类型:template.HTML。呈现模板时,模板中此类型的值不会转义。

因此将 WebPageHTMLItems.SonoffBasic 的类型更改为 template.HTML,它将按原样呈现:

type WebPageHTMLItems struct{
    SonoffBasic template.HTML
}

template.HTML 具有 string 作为其基础类型,因此要从 string 值设置此字段,请使用简单的类型转换:

params := &WebPageHTMLItems{
    SonoffBasic: template.HTML("<div>...</div>"),
}

警告:这不能防止代码注入!因此,例如,当您替换 %title% 并且它包含 JavaScript 代码时,该代码将通过输出并最终在客户端的浏览器中执行。

使用 {{template}} 操作

另请注意,您可以将 <div> 定义为单独的命名模板,然后只需使用 {{template}} 操作将其包含在您的页面中,如下所示:

{{define "sonoffbasicdevice"}}
    <div id="sonoffbasicdevice">
        <span class="%connectiondotclass%"></span>
        <p id="title">%title%</p>
        <p id="tempandhum">%humstatus%</p>
        <p id="ipaddress">%ipaddress%</p>
        <p id="portnumber">%portnumber%</p>
    </div>
{{end}}

在您的页面模板中:

<div id="wrapper" width="100%">
    {{template "sonoffbasicdevice"}}
</div>

另请注意,为了完全安全起见,您也可以像其他任何模板一样制作并传递参数给您的 sonoffbasicdevice 模板,并让 html/template 包负责安全, 上下文相关替换:

{{define "sonoffbasicdevice"}}
    <div id="sonoffbasicdevice">
        <span class="{{.Connectiondotclass}}"></span>
        <p id="title">{{.Title}}</p>
        <p id="tempandhum">{{.Humstatus}}</p>
        <p id="ipaddress">{{.Ipaddress}}</p>
        <p id="portnumber">{{.Portnumber}}</p>
    </div>
{{end}}

然后你必须像这样包含它(传递用于它的参数):

<div id="wrapper" width="100%">
    {{template "sonoffbasicdevice" .SonoffBasic}}
</div>

此 "multi-template" 的执行可能如下所示:

type SonoffBasic struct {
    Connectiondotclass string
    Title              string
    Humstatus          string
    Ipaddress          string
    Portnumber         string
}

type WebPageHTMLItems struct{
    SonoffBasic *SonoffBasic
}

params := &WebPageHTMLItems{
    SonoffBasic: &SonoffBasic{
        Connectiondotclass: "someclass",
        Title:              "sometitle",
        Humstatus:          "somestatus",
        Ipaddress:          "someip",
        Portnumber:         "someport",
    },
}

err := templates.ExecuteTemplate(w, "index.html", params)