3 回答
TA贡献1852条经验 获得超1个赞
中间件链
这个问题的一个常见解决方案是所谓的中间件链。有几个库提供此功能,例如negroni。
这是一种延续传递风格的形式,您可以像这样编写中间件函数(取自 negroni 的自述文件):
func MyMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
// do some stuff before
next(rw, r)
// do some stuff after
}
然后 negroni 为您提供一个 HTTP 处理程序,以正确的顺序调用您的中间件。
我们可以以稍微不同的方式实现这个解决方案,而不是一种不太神奇但功能更多的方法(如在函数式编程中)。定义处理程序组合子如下:
func NewFooHandler(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// do some stuff before
next(r,w)
// do some stuff after
}
}
然后将您的链定义为一个组合:
h := NewFooHandler(NewBarHandler(NewBazHandler(Sink)))
现在h是http.HandlerFuncfoo,然后是 bar,然后是 baz。Sink只是一个空的最后一个处理程序,什么都不做(“完成”链。)
将此解决方案应用于您的问题
定义一个处理程序组合子:
func NewResponseLoggingHandler(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// switch out response writer for a recorder
// for all subsequent handlers
c := httptest.NewRecorder()
next(c, r)
// copy everything from response recorder
// to actual response writer
for k, v := range c.HeaderMap {
w.Header()[k] = v
}
w.WriteHeader(c.Code)
c.Body.WriteTo(w)
}
}
现在问题归结为处理程序管理。您可能希望将此处理程序应用于某个类别中的所有链。为此,您可以再次使用组合器(这在某种程度上相当于 negroni 的Classic()方法):
func NewDefaultHandler(next http.HandlerFunc) http.HandlerFunc {
return NewResponseLoggingHandler(NewOtherStuffHandler(next))
}
在此之后,每当您启动这样的链时:
h := NewDefaultHandler(...)
它将自动包含响应日志记录和您在NewDefaultHandler.
- 3 回答
- 0 关注
- 207 浏览
添加回答
举报