在golang中处理模板错误的惯用方法

cho*_*wey 8 go go-templates

说我有html/template类似以下内容:

<html>
<body>
    <p>{{SomeFunc .SomeData}}</p>
</body>
Run Code Online (Sandbox Code Playgroud)

有时会SomeFunc返回错误.有没有惯用的方法来解决这个问题?

如果我直接写入ResponseWriter,则在遇到错误之前已经写入了状态代码200.

var tmpl *template.Template

func Handler(w http.ResponseWriter, r *http.Request) {
    err := tmpl.Execute(w, data)
    // "<html><body><p>" has already been written...
    // what to do with err?
}
Run Code Online (Sandbox Code Playgroud)

我最好返回一个状态代码400或其他一些,但如果我template.Execute直接使用,我就看不到这样做的方法ResponseWriter.有什么我想念的吗?

icz*_*cza 8

由于模板引擎即时生成输出,因此SomeFunc调用之前的模板部分已经发送到输出.如果输出没有缓冲,则可能已经发送了它们(以及HTTP 200状态).

你无能为力.

你可以做的是在打电话之前进行检查template.Execute().在琐碎的情况下,它应该足以调用SomeFunc()并检查其返回值.如果选择此路径并且返回值SomeFunc()很复杂,则不必再从模板中调用它,只需将其返回值传递给传递给模板的参数,并在模板中引用该值(所以SomeFunc()不必执行两次).

如果这还不够或您无法控制它,您可以创建一个bytes.Buffer,执行指向此缓冲区的模板,并在Execute()返回后检查是否有错误.如果有错误,请发回适当的错误消息/页面.如果一切顺利,您只需将缓冲区的内容发送到ResponseWriter.

这看起来像这样:

buf := &bytes.Buffer{}
err := tmpl.Execute(buf, data)
if err != nil {
    // Send back error message, for example:
    http.Error(w, "Hey, Request was bad!", http.StatusBadRequest) // HTTP 400 status
} else {
    // No error, send the content, HTTP 200 response status implied
    buf.WriteTo(w)
}
Run Code Online (Sandbox Code Playgroud)

  • I**[写了这篇文章](http://elithrar.github.io/article/approximating-html-template-inheritance/)**一段时间 - 通过`sync.Pool`或其他构造 - 一个缓冲池 - 是一种稍微提高性能的方法来解决这个问题.分配一个池,获取一个缓冲区,写入它然后再响应(在nil错误时),然后将缓冲区放回池中.否则你就点了! (5认同)