猿问

恐慌:最后一个参数需要是 http.HandlerFunc 类型

我有这个辅助函数,可以正常编译:


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

有谁知道为什么在这种情况下该类型断言会失败?没有意义。也许我实际上并没有检索切片的最后一个参数之类的?有没有更好的方法从切片中弹出最后一个参数?


蓝山帝景
浏览 115回答 2
2回答

函数式编程

您需要使用 .将mw.Middleware()语句的第二个参数包装到类型中。http.Handlerhttp.HandlerFunc()func (h Handler) makeGetMany(v Injection) http.HandlerFunc {&nbsp; &nbsp; return mw.Middleware(&nbsp; &nbsp; &nbsp; &nbsp; mw.Allow("admin"),&nbsp; &nbsp; &nbsp; &nbsp; http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; log.Println("now we are sending response.");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; json.NewEncoder(w).Encode(v.Share)&nbsp; &nbsp; &nbsp; &nbsp; }),&nbsp; &nbsp; )}

catspeake

在 http 包中, ListenAndServe具有以下签名func ListenAndServe(addr string, handler Handler) error其中Handler(ie, 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不是 a 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. 看看它是如何工作的也很有趣。// 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调用自身的方法。
随时随地看视频慕课网APP

相关分类

Go
我要回答