英文:
Overriding ResponseWriter interface to catch HTTP errors
问题
我正在使用Go编写一个Web应用程序,虽然各种mux库提供了设置自定义404错误处理程序的方法,但对于其他4xx和5xx错误代码却没有相应的处理方式。
一个建议是在ResponseWriter接口中重写WriteHeader方法并检查状态码,但我对如何实际编写这个方法感到困惑(在输出之前重写ResponseWriter方法)。可以在negroni包中找到一个可能的示例。
这是否是为4xx和5xx错误提供自定义模板的正确方法?有人可以提供一个实现示例吗?
更新
非常感谢David和elithrar的回答和代码。David编写的Interceptor
结构可以用作服务器mux的包装器,如elithrar在评论中所示。对于那些想要进一步了解为什么以及如何工作的人,astaxie的书中的这一部分提供了关于net/http包的工作原理的非常好的信息,还可以查看net/http包的server.go源代码。
英文:
I'm coding a web application in Go, and while various mux libraries provide a way to set a custom 404 error handler, there's nothing for other 4xx and 5xx error codes.
One suggestion is to override the WriteHeader method in the ResponseWriter interface and check the status code, but I'm confused as to how this would actually be written (the overriding of ResponseWriter methods, before outputting). One possible example can be found from the negroni package.
Would this be the correct way to serve a custom template for 4xx and 5xx errors? Could anyone provide an example of how this could be implemented?
Update
Big thanks to David and elithrar for their responses and code. The Interceptor
struct that David coded can be used in a wrapper for the server mux, as elithrar shows in the comments. For those looking for further explanation as to why and how this works, this section from astaxie's book gives some very good info on the workings of the net/http package, along with viewing the server.go source code from the net/http package.
答案1
得分: 5
mux库只提供了设置未找到处理程序的方法,以便为您提供一种拦截无法解析URL到已知映射的请求的方式。
例如,您可以这样做:
mux.Handle("/foo", fooFunc)
mux.Handle("/bar", barFunc)
但是客户端访问/baz
,而mux没有映射。
它们实际上并没有拦截发送给客户端的404,只是在遇到此问题时调用未找到处理程序。
此外,如果您的/foo处理程序发送404响应,未找到处理程序不会被调用。
如果您希望为映射URL的各种返回响应设置自定义页面,只需使各个处理程序编写正确的响应即可。
如果您无法控制该逻辑(即:框架正在编写某些内容并且无法覆盖),那么您可能希望拦截所有请求并使用响应代码检测逻辑覆盖http.ResponseWriter。
这是一个基本上实现您要求的示例拦截器。在Play上查看。
package main
import (
"fmt"
"log"
)
import "net/http"
type Interceptor struct {
origWriter http.ResponseWriter
overridden bool
}
func (i *Interceptor) WriteHeader(rc int) {
switch rc {
case 500:
http.Error(i.origWriter, "Custom 500 message / content", 500)
case 404:
http.Error(i.origWriter, "Custom 404 message", 404)
case 403:
i.origWriter.WriteHeader(403)
fmt.Fprintln(i.origWriter, "Custom 403 message")
default:
i.origWriter.WriteHeader(rc)
return
}
// 如果默认情况没有执行(并返回),则我们必须已经覆盖了输出
i.overridden = true
log.Println(i.overridden)
}
func (i *Interceptor) Write(b []byte) (int, error) {
if !i.overridden {
return i.origWriter.Write(b)
}
// 如果我们覆盖了响应,则不返回任何内容。
return 0, nil
}
func (i *Interceptor) Header() http.Header {
return i.origWriter.Header()
}
英文:
The mux libraries only have a means of setting the not found handler as a means of giving you a way to intercept requests where the mux can't resolve the URL to it's known mappings.
For example, you do:
mux.Handle("/foo",fooFunc)
mux.Handle("/bar",barFunc)
But the client accesses /baz
to which the mux has no mapping.
They do not actually intercept a 404 going to the client, they just invoke the not found handler when it runs in to this problem.
Also, if your /foo handler sends a 404 response, the not found does not get invoked.
If you want custom pages for various return responses from your mapped URLs, simply make the various handlers write the correct response.
If you don't control that logic (ie: the framwork is writing something and has no means to override), then you may want to intercept all requests and override the http.ResposeWriter with response code detection logic.
Here's an example interceptor that basically does what you want. On Play
package main
import (
"fmt"
"log"
)
import "net/http"
type Interceptor struct {
origWriter http.ResponseWriter
overridden bool
}
func (i *Interceptor) WriteHeader(rc int) {
switch rc {
case 500:
http.Error(i.origWriter, "Custom 500 message / content", 500)
case 404:
http.Error(i.origWriter, "Custom 404 message", 404)
case 403:
i.origWriter.WriteHeader(403)
fmt.Fprintln(i.origWriter, "Custom 403 message")
default:
i.origWriter.WriteHeader(rc)
return
}
// if the default case didn't execute (and return) we must have overridden the output
i.overridden = true
log.Println(i.overridden)
}
func (i *Interceptor) Write(b []byte) (int, error) {
if !i.overridden {
return i.origWriter.Write(b)
}
// Return nothing if we've overriden the response.
return 0, nil
}
func (i *Interceptor) Header() http.Header {
return i.origWriter.Header()
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论