当我阅读文章https://upgear.io/blog/golang-tip-wrapping-http-response-writer-for-middleware/?utm_source=golangweekly&utm_medium=email时,我意识到很容易制作一个包装器(设计模式代理),它包装了一些方法。
情况有点复杂,当你不想要松开界面时,包裹的对象有它。
在示例中,我已经编写了如何选择性地实现http.Flusher的方法。但是如何解决文章中的情况,当w可以实现3个接口中的一些时(http.Flusher,http.Hijacker,http.Pusher)。这是更好的解决方案,写出8种不同的类型,其中每种都实现了之前的组合?
// add type, that do what statusRecorder, but keeps ability to be Flusher
type statusRecordFlusher statusRecorder
func (w *statusRecordFlusher) Flush() {
w.ResponseWriter.(http.Flusher).Flush()
}
// and decision, how to wrap
func logware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Initialize the status to 200 in case WriteHeader is not called
var rec http.ResponseWriter
if _, ok := w.(http.Flusher); ok {
rec = &statusRecordFlusher{w, 200}
} else {
rec = &statusRecorder{w, 200}
}
next.ServeHTTP(rec, r)
})
}
答案 0 :(得分:0)
您正在嵌入ResponseWriter
,并且在不添加任何行为的情况下隐藏Flush
;删除阴影方法。您仍然需要进行某种类型的争论,但除非您尝试添加或更改行为(大概只是WriteHeader
,否则您不需要执行任何方法实施)。
因为您只是尝试在此处公开嵌入类型的方法,所以您甚至不需要定义所有结构,您可以使用匿名结构(playground example here):
type statusRecorder struct {
// Not sure what all is in here but let's assume at least:
http.ResponseWriter
status int
}
func logware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Per the docs:
// The default ResponseWriter for HTTP/1.x connections supports Hijacker, but HTTP/2 connections intentionally do not.
// Pusher is the interface implemented by ResponseWriters that support HTTP/2 server push.
// Therefor w will only ever be a Hijacker or a Pusher, never both.
sr := &statusRecorder{w, 200}
if h, ok := w.(http.Hijacker); ok {
if f, ok := w.(http.Flusher); ok {
w = &struct {
http.ResponseWriter
http.Hijacker
http.Flusher
}{sr, h, f}
} else {
w = &struct {
http.ResponseWriter
http.Hijacker
}{sr, h}
}
} else if p, ok := w.(http.Pusher); ok {
if f, ok := w.(http.Flusher); ok {
w = &struct {
http.ResponseWriter
http.Pusher
http.Flusher
}{sr, p, f}
} else {
w = &struct {
*statusRecorder
http.Pusher
}{sr, p}
}
} else {
w = sr
}
next.ServeHTTP(w, r)
})
}