Я изучаю Go и использую gin-gonic для веб-приложения. Я пытаюсь изящно восстановиться после ошибок шаблона и не смог выяснить, как буферизовать выходные данные или правильно перенаправить для достижения этой цели.
С этим кодом:
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
g := gin.New()
g.LoadHTMLGlob("templates/*")
g.Use(func(c *gin.Context) {
defer func() {
if err := recover(); err != nil {
c.HTML(http.StatusInternalServerError, "error.tmpl", nil)
}
}()
c.Next()
})
g.GET("/", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.tmpl", gin.H{"var": 4})
})
g.Run(":80")
}
, где templates / index.tmpl равен
Before
<br>
Bad: {{.var.x}}
<br>
After
и templates / error.tmpl равно
Oops! We encountered an error.
когда я загружаю свою страницу, я вижу
Before
Bad: Oops! We encountered an error.
и код ответа заканчивается на 200. Я бы предпочел аккуратно перехватить ошибку, чтобы единственное, что отображалось пользователю, было
Oops! We encountered an error.
код ответа выходит как 500, и ошибка регистрируется на сервере для дальнейшего расследования.
Какой лучший способ в gin отлавливать ошибки шаблона, не показывая частичный вывод пользователю? Я видел несколько примеров выполнения этой задачи с помощью буферизации с использованием встроенного содержимого net / http, но я не смог найти ничего, что помогло бы справиться с этим в gin.
Отредактировано с решением
Основываясь на комментариях @big голубя к принятому ответу, я сам запустил шаблон в буфер и использовал c.Data()
, чтобы отобразить его, если ошибок не было. Это все еще кажется далеко не идеальным, поскольку оно обходит такие функции, как способность multitemplate
динамически перезагружать проанализированный шаблон во время выполнения в сборках dev, но это работает. Обновленный код проверки концепции выглядит следующим образом:
package main
import (
"bytes"
"html/template"
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
g := gin.New()
g.LoadHTMLGlob("templates/*")
g.Use(func(c *gin.Context) {
defer func() {
if err := recover(); err != nil {
c.HTML(http.StatusInternalServerError, "error.tmpl", nil)
}
}()
c.Next()
})
g.GET("/", func(c *gin.Context) {
if tmpl, err := template.ParseFiles("templates/index.tmpl"); err != nil {
panic(err)
} else {
buf := &bytes.Buffer{}
if err = tmpl.Execute(buf, gin.H{"var": 4}); err != nil {
panic(err)
} else {
c.Data(http.StatusOK, "text/html; charset=utf-8", buf.Bytes())
}
}
})
g.Run(":80")
}
Использование пула буферов, шаблонов предварительного анализа и других подобных тонкостей оставлено в качестве упражнения для будущих читателей.
Если кто-нибудь знает, как лучше справиться с этим, не обходя возможности анализа / рендеринга джина, я очень открыт для этого.