处理 Golang 模板错误的惯用方式

13

假设我有以下的 html/template

<html>
<body>
    <p>{{SomeFunc .SomeData}}</p>
</body>

有时候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?
}

最好返回状态码400或类似的,但如果我直接在ResponseWriter上使用template.Execute,我看不到实现这一点的方法。我有什么遗漏吗?

1个回答

16

由于模板引擎是动态生成输出的,调用 SomeFunc 前的模板部分已经被发送到输出流中。如果输出没有缓冲,这些内容(包括 HTTP 200 状态码)可能已经被发送。

你无法做任何事情来解决这个问题。

你可以在调用 template.Execute() 之前进行检查。在简单的情况下,调用 SomeFunc() 并检查其返回值应该就足够了。如果你选择这种方式,并且 SomeFunc() 的返回值很复杂,则不必在模板中再次调用它,只需将其返回值传递给模板参数并在模板中引用此值即可(因此不必执行两次 SomeFunc() )。

如果这不够或者无法控制,你可以创建一个 bytes.Bufferstrings.Builder,将模板执行指向该缓冲区,在 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)
}

7
我之前曾经写过关于这个话题的文章(请点击此处查看)——通过 sync.Pool 或其他结构来实现缓冲池是一个稍微更高效的解决方案。分配一个池,获取一个缓冲区,向其写入内容再将其响应输出(在没有错误的情况下),然后将缓冲区放回池中。除此之外,你说得很对! - elithrar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接