首页 > 解决方案 > 优雅地处理 gin-gonic 中的模板渲染错误

问题描述

我正在学习 Go 并将 gin-gonic 用于 Web 应用程序。我试图从模板错误中优雅地恢复,但无法弄清楚如何缓冲输出或正确重定向以实现这一目标。

使用此代码:

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")
}

模板/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,错误会记录在服务器上以供以后调查。

在不向用户显示部分输出的情况下,在杜松子酒中捕获模板错误的最佳方法是什么?我已经看到了几个使用内置的 net/http 东西通过缓冲来实现这一点的例子,但是还没有找到任何在 gin 中处理它的好方法。

用解决方案编辑

基于@big pigeon 对已接受答案的评论,我最终自己将模板执行到缓冲区中,并c.Data()在没有错误的情况下使用它来显示它。这似乎仍然不太理想,因为它绕过了诸如multitemplate在开发构建中在运行时动态重新加载已解析模板的功能,但它确实有效。更新后的概念验证代码如下所示:

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")
}

使用缓冲池、预解析模板和其他类似的细节留给任何未来的读者作为练习。

如果有人知道在不绕过杜松子酒的解析/渲染功能的情况下更好地处理这个问题的方法,我很愿意接受。

标签: gogo-gin

解决方案


您必须确保模板正确呈现,因为 c.HTML 将直接写入响应,此时一些字节已发送到客户端。

您可以使用“html/template”,并使用 buff 缓存响应数据,而不是直接写入响应写入器


推荐阅读