我有这个辅助函数,可以正常编译:
func Middleware(adapters ...interface{}) http.HandlerFunc {
log.Info("length of adapters:", len(adapters))
if len(adapters) < 1 {
panic("Adapters need to have length > 0.");
}
h, ok := (adapters[len(adapters)-1]).(http.HandlerFunc)
if ok == false {
panic("Last argument needs to be of type http.HandlerFunc") // ERROR HERE
}
adapters = adapters[:len(adapters)-1]
for _, adapt := range adapters {
h = (adapt.(AdapterFunc))(h)
}
return h
}
我这样称呼它:
router.HandleFunc("/share", h.makeGetMany(v)).Methods("GET")
func (h Handler) makeGetMany(v Injection) http.HandlerFunc {
return mw.Middleware(
mw.Allow("admin"),
func(w http.ResponseWriter, r *http.Request) {
log.Println("now we are sending response.");
json.NewEncoder(w).Encode(v.Share)
},
)
}
问题是我遇到此错误,我无法弄清原因:
panic: Last argument needs to be of type http.HandlerFunc goroutine 1 [running]: huru/mw.Middleware(0xc420083d40, 0x2, 0x2, 0xc42011f3c0) /home/oleg/codes/huru/api/src/huru/mw/middleware.go:301 +0x187 huru/routes/share.Handler.makeGetMany(0xc4200ae1e0, 0x10) /home/oleg/codes/huru/api/src/huru/routes/share/share.go:62 +0x108
它确实确认适配器切片的长度为2:
length of adapters:2
有人知道为什么这种类型的断言在这种情况下会失败吗?没有意义。也许我实际上不是在检索切片的最后一个参数或其他内容?有没有更好的方法可以将最后一个参数弹出切片?
答案 0 :(得分:3)
您需要使用mw.Middleware()
将http.Handler
语句的第二个参数包装为http.HandlerFunc()
类型。
func (h Handler) makeGetMany(v Injection) http.HandlerFunc {
return mw.Middleware(
mw.Allow("admin"),
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Println("now we are sending response.");
json.NewEncoder(w).Encode(v.Share)
}),
)
}
答案 1 :(得分:1)
在http包中, ListenAndServe具有以下签名
func ListenAndServe(addr string, handler Handler) error
其中Handler
(即http.Handler
)是接口
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
对于一个Web应用程序,只有一个ListenAndServe
调用,因此只有一个handler
,它需要处理所有访问点,例如/url1
,/url2
等等。如果我们从头开始编写handler
,则该实现可能是一个自定义的struct
,它环绕数据库句柄。它的ServeHTTP
方法检查访问点,并将相应的内容写入ResponseWriter
,这很繁琐和混杂。
这就是ServeMux的动机,它就是您代码中的router
。它具有ServeHTTP方法,因此它满足http.Handler
接口,并且可以用于ListenAndServe
。此外,它具有HandleFunc
方法来处理各个访问点
func (mux *ServeMux) HandleFunc(pattern string,
handler func(ResponseWriter, *Request))
请注意,此处的handler
不是http.Handler
,即它没有ServeHTTP
方法。不必这样做,因为mux
已经拥有ServeHTTP
,并且其ServeHTTP
方法可以将单个访问点请求分派到相应的处理程序。
请注意,它还有一个Handle
方法,该方法要求参数满足http.Handler
接口。与HandleFunc
方法相比,使用起来不太方便。
func (mux *ServeMux) Handle(pattern string, handler Handler)
现在回到您的问题,因为您调用router.HandleFunc
,所以它的输入不必是http.Handler
。因此,另一种解决方案是使用func(ResponseWriter, *Request)
作为中间件和makeGetMany
方法的返回类型。 (中间件中的类型断言也需要更新,可能还需要更新更多代码)
@xpare的解决方案是进行类型转换,以便所有功能签名都匹配,即将func(ResponseWriter, *Request)
转换为http.HandlerFunc
。看看它如何工作也很有趣。从implementation
// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f.
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
您会看到它基本上定义了一个ServeHTTP
方法来调用自身。