【问题标题】:Parsing HTML code in page shown as plain text with go Template使用 go Template 解析页面中的 HTML 代码显示为纯文本
【发布时间】:2018-05-18 09:48:34
【问题描述】:

我已经开始使用 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)
} 

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

type WebPageHTMLItems struct{
    SonoffBasic  string
}

其中的 SonoffBasic 字符串包含所有已填充信息的 div。

我运行程序时可以查看网页,但是当我显示网页时,不是解析div,而是显示为纯文本,我在这里做错了什么?

这甚至是将数据解析为 HTML 文件的正确方法吗?我之所以使用这种添加完整 div 的方式,是因为我可以有多个“sonoffbasicdevice”项,并且应该添加多个。

【问题讨论】:

标签: html go go-templates


【解决方案1】:

使用template.HTML

html/template 提供针对代码注入的自动、上下文相关的转义安全:

HTML 模板将数据值视为应编码的纯文本,以便它们可以安全地嵌入到 HTML 文档中。转义是上下文相关的,因此动作可以出现在 JavaScript、CSS 和 URI 上下文中。

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}} 操作

还请注意,您可以将 &lt;div&gt; 定义为一个单独的命名模板,然后只需使用 {{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>

这个“多模板”的执行可能如下所示:

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)

【讨论】:

  • 感谢您对我如何实现 div 的详细说明。甚至告诉我如何才能做得更好,我会先寻求简单的解决方案,看看我是否能让 HTML 页面正常工作。然后使用{{template}} 操作重写它。这样可以生成更安全、更美观的代码
猜你喜欢
  • 1970-01-01
  • 2015-05-27
  • 1970-01-01
  • 2018-07-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-21
  • 1970-01-01
相关资源
最近更新 更多