Golang中如何转义A标签href属性中的保留字符

Golang中如何转义A标签href属性中的保留字符 我使用 html/template 生成 HTML,但在 a 标签的 href 属性中,保留字符被 html/template 转义了。

我知道根据 RFC 3986,保留字符不应被转义。如何避免在 href 属性中转义保留字符?

例如…

dict := make(map[string]interface{})
dict["link"] = `https://example.com/()"`
tag := `<a href="{{ $.link }}"></a>`
t, _ := template.New("tag").Parse(tag)

var tpl bytes.Buffer
e := t.Execute(&tpl, dict)
if e != nil {
    fmt.Println(e)
}

fmt.Println(tpl.String())


// <a href="https://example.com/%28%29%22"></a>

我期望的结果是

// <a href="https://example.com/()"></a>

更多关于Golang中如何转义A标签href属性中的保留字符的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

这两个URL是同一资源的不同等价表示。

更多关于Golang中如何转义A标签href属性中的保留字符的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


两者都正确吗? 我认为根据 RFC 3986 规范,并未执行百分号编码。

尽管您可以直接使用许多字符,但始终可以使用百分比编码。

例如,“A”可以直接书写,但 %41 必须被视为等效。

// 代码示例:演示百分比编码处理
func main() {
    // 直接字符和编码字符应被同等处理
    fmt.Println("直接字符: A")
    fmt.Println("编码字符: %41")
}

html/template 中,href 属性默认会被 URL 转义。要避免转义保留字符,可以使用 template.URL 类型包装你的 URL 字符串。

package main

import (
    "bytes"
    "fmt"
    "html/template"
)

func main() {
    dict := make(map[string]interface{})
    dict["link"] = template.URL(`https://example.com/()"`)
    tag := `<a href="{{ $.link }}"></a>`
    t, _ := template.New("tag").Parse(tag)

    var tpl bytes.Buffer
    e := t.Execute(&tpl, dict)
    if e != nil {
        fmt.Println(e)
    }

    fmt.Println(tpl.String())
    // 输出: <a href="https://example.com/()"></a>
}

template.URL 类型实现了 template.URL 接口,告诉模板引擎这个值已经是安全的 URL,不需要额外转义。注意双引号 " 仍然会被转义,因为它在 HTML 属性值中是特殊字符。

对于更复杂的场景,比如需要保留查询参数中的保留字符:

dict["link"] = template.URL(`https://example.com/path?query=foo&bar=baz&special=()*`)
// 输出: <a href="https://example.com/path?query=foo&bar=baz&special=()*"></a>

如果 URL 中包含用户输入,需要确保安全性:

import "net/url"

func safeURL(rawURL string) (template.URL, error) {
    parsed, err := url.Parse(rawURL)
    if err != nil {
        return "", err
    }
    // 验证协议,防止 javascript: 等危险协议
    if parsed.Scheme != "http" && parsed.Scheme != "https" {
        return "", fmt.Errorf("unsupported scheme")
    }
    return template.URL(rawURL), nil
}

// 使用
safe, err := safeURL(userInput)
if err != nil {
    // 处理错误
}
dict["link"] = safe

对于需要完全控制 URL 编码的情况,可以手动处理:

dict["link"] = template.URL(`https://example.com/` + url.PathEscape(`path with spaces`) + `?q=` + url.QueryEscape(`query with & and =`))

这样可以在不同部分应用适当的编码规则。

回到顶部