2017-05-14 147 views
2

在使用julienschmidt/httprouter时链接中间件的最佳方式是什么?如何在goLang中使用julienschmidt/httprouter时使用中间件?

据我所搜索到的,http.HandlerFunc只接受函数func (w ResponseWriter, r *Request)的形式,而httprouter.Handle函数的形式是func (w http.ResponseWriter, r *http.Request, ps httprouter.Params)

如何在不将httprouter.Handle函数转换为http.HandlerFunc的情况下链接中间件?

例如:
我routes.go是形式的,

router := httprouter.New() 
router.POST("/api/user/create", middlewares.EscapeStringsMiddleware(User.CreateUser)) 
log.Fatal(http.ListenAndServe(":8000", router)) 

我怎样写中间件功能为上述路线?

已经尝试过的方法:获得

1.

func EscapeStringsMiddleware(next http.Handler) httprouter.Handle { 

    return func (response http.ResponseWriter, request *http.Request, ps httprouter.Params) { 
     err := request.ParseForm() 
     if err != nil { 
      panic(err) 
     } 

     for key, values := range request.Form { 
      for i, value := range values { 
       value = template.HTMLEscapeString(value) 
       value = template.JSEscapeString(value) 
       request.Form[key][i] = value 
      } 
     } 
     next.ServeHTTP(response, request) 
    } 
} 

错误:

cannot use User.CreateUser (type func(http.ResponseWriter, *http.Request, httprouter.Params)) as type http.Handler in argument to middlewares.EscapeStringsMiddleware: 
func(http.ResponseWriter, *http.Request, httprouter.Params) does not implement http.Handler (missing ServeHTTP method) 

2.

func EscapeStringsMiddleware(next httprouter.Handle) httprouter.Handle { 

    return func (response http.ResponseWriter, request *http.Request, ps httprouter.Params) { 
     err := request.ParseForm() 
     if err != nil { 
      panic(err) 
     } 

     for key, values := range request.Form { 
      for i, value := range values { 
       value = template.HTMLEscapeString(value) 
       value = template.JSEscapeString(value) 
       request.Form[key][i] = value 
      } 
     } 
     next.ServeHTTP(response, request) 
    } 
} 

错误获得:

next.ServeHTTP undefined (type httprouter.Handle has no field or method ServeHTTP) 

而且我怎么串联多个中间件?

例如,

router.POST("/api/user/create", middlewares.VerifyCSRF(middlewares.EscapeStringsMiddleware(User.CreateUser))) 

回答

4

这个问题是不是与你的中间件处理程序。由于User.CreateUser不是http.Handler类型,因此您会发生错误。

尝试这种模式:

最重要的一点是要返回http.Handlerhttp.HandlerFunc包裹func(w http.ResponseWriter, r *http.Request)

func Handler() http.Handler { 
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 
     // do stuff 
    }) 
} 

走来源:

// 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) 
} 

根据大家的反馈:

httprouter.Handle没有实现ServeHTTP。它被直接调用。例如:next(w, r, ps)

下面您会找到中间件处理程序的示例。

// Middleware without "github.com/julienschmidt/httprouter" 
func StdToStdMiddleware(next http.Handler) http.Handler { 

    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 
     // do stuff 
     next.ServeHTTP(w, r) 
    }) 
} 

// Middleware for a standard handler returning a "github.com/julienschmidt/httprouter" Handle 
func StdToJulienMiddleware(next http.Handler) httprouter.Handle { 

    return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { 
     // do stuff 
     next.ServeHTTP(w, r) 
    } 
} 

// Pure "github.com/julienschmidt/httprouter" middleware 
func JulienToJulienMiddleware(next httprouter.Handle) httprouter.Handle { 

    return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { 
     // do stuff 
     next(w, r, ps) 
    } 
} 

func JulienHandler() httprouter.Handle { 
    return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { 
     // do stuff 
    } 
} 

func StdHandler() http.Handler { 
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 
     // do stuff 
    }) 
} 

func main() { 
    router := httprouter.New() 
    router.POST("/api/user/create", StdToJulienMiddleware(StdHandler())) 
    router.GET("/api/user/create", JulienToJulienMiddleware(JulienHandler())) 
    log.Fatal(http.ListenAndServe(":8000", router)) 
} 
+0

User.CreateUser的类型是httprouter.Handle即'FUNC(w的http.ResponseWriter,R * http.Request,PS httprouter.Params)'。我也会考虑传递参数给这个函数。另外,如果我链接多个中间件,那么这个代码在父中间件中如何变化? 即 ''' –

+0

@RohithBalaji发布了一个带有错误的完整可运行示例,那么我可以说更多的路由器(更好的方法是使用路由器) –

+0

@RohithBalaji我更新了我的答案 –

0

https://github.com/cnvrtly/adaptr从lib,其中适配器也被添加到链请求中间件功能。

func compatibleHandler(h http.Handler, httprParamsCtxKey interface{}) httprouter.Handle { 
return toHttpRouterHandle(h, httprParamsCtxKey) 
} 
func toHttpRouterHandle(h http.Handler, httprParamsCtxKey interface{}) func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { 
    return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { 
    if httprParamsCtxKey != nil { 
     r = SetCtxValue(r, httprParamsCtxKey, p) 
    } 
    h.ServeHTTP(w, r) 
    } 
} 

如果您正在寻找例如/想法如何定义路线:https://github.com/cnvrtly/golang-appengine-seed