你正在使用的Go版本是什么( go version
)?
go1.11
这个问题在最新版本的发布中是否重现?
是的
你正在使用什么操作系统和处理器架构( go env
)?
GOARCH="amd64"
GOBIN="/home/jabenze/go/bin"
GOCACHE="/home/jabenze/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/jabenze/go"
GOPROXY=""
GORACE=""
GOROOT="/usr/lib/go"
GOTMPDIR=""
GOTOOLDIR="/usr/lib/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build876174949=/tmp/go-build -gno-record-gcc-switches"
你做了什么?
按照"编写Web应用程序"教程,从这里开始,直到错误处理部分:https://golang.org/doc/articles/wiki/#tmp_9。
查看函数 renderTemplate
,如下所示:
func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
t, err := template.ParseFiles(tmpl + ".html")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
err = t.Execute(w, p)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
修改 Page
数据结构,通过删除一个字段(或修改模板以引用不存在的字段),使得以下行: err = t.Execute(w, p)
导致创建一个错误。观察应用程序发送的响应代码。下一行: http.Error(w, err.Error(), http.StatusInternalServerError)
意味着响应代码为500,但是应用程序返回了200。
这是因为 t.Execute
调用了 w.Write
,由于 w.WriteHeader
尚未被调用,导致对 w.WriteHeader(200)
的隐式调用。对 w.WriteHeader
的进一步调用,例如 http.Error
内的调用将被忽略。
在所有错误的情况下,无法发送500错误代码,因为 w.Write
本身可以返回错误,在某个时候,只需简单地记录错误并返回而不设置错误代码即可。可选地,示例可以渲染到 bytes.Buffer
,以便捕获模板渲染错误。
你期望看到什么?
基于代码,500错误代码
你看到了什么?
错误代码200。
5条答案
按热度按时间r8xiu3jd1#
这是一个有效的问题,很好的发现!感谢你编写的报告和良好的分析。
我们应该讨论如何解决它。正如你所说,一个选项是先将模板渲染到
bytes.Buffer
,然后在所有可能失败的操作都成功后,只将buf
复制到rw
。然而,这可能与教程的其他部分不太相符。还有其他方法可以解决这个问题,重要的是要提出一个在“编写Web应用程序”教程的背景下最有意义的解决方案,以及读者在那之前期望了解或接触到的内容。
/cc @adg 作为文章的原始作者,我认为。
cx6n0qe32#
字节缓冲区渲染的唯一问题是,如果教程要涵盖适当的错误处理,我们仍然会遇到同样的问题。
对于教程的建议可能是直接将模板渲染错误写入
ResponseWriter
和log
,然后在教程中添加一个注解或简短的说明,说明为什么我们不能写入两次头部。这是正确的代码,不会使教程变得过于复杂。不知道是否有我遗漏的更简单的解决方案。
pgccezyw3#
我对于教程的建议可能仅仅是继续直接写入ResponseWriter并记录模板渲染错误。
这就是我想说的。模板渲染错误对应用程序作者来说,而不是用户,并且通常只应该在程序开发期间发生。在这里记录它将是理想的,并且几句话解释这一点实际上会改善教程。
vuv7lop34#
https://golang.org/cl/136757提到了这个问题:
doc/articles/wiki: remove misleading code in tutorial
2eafrhcq5#
我意识到这个问题仍然带有"需要决策"的标签,但由于到目前为止所有人都同意,所以我继续写了一些东西来解决它。我不是最好的作家,但至少这是一个不错的开始。