从切片中嵌套函数

时间:2017-09-19 05:46:36

标签: go slice middleware

我正在构建一个Go web应用程序,在处理路由时支持各种中间件功能。我试图尽可能地坚持net/http并想知道如何在不使用像 negroni 这样的中间件库的情况下实现这一目标。

基本上我想做的是能够提供一片中间件函数,比如一个用于记录,一个用于检查有效的JWT,最后是处理请求的处理程序。

通过定义以下结构,我能够通过negroni做到这一点:

// Route ..
type Route struct {
  Method     string
  Path       string
  Middleware []negroni.Handler
  Handler    http.HandlerFunc
}

然后定义一条路线,如:

var commonRoutes = []Route{
    {
        Method:     "GET",
        Path:       "/info",
        Middleware: []negroni.Handler{negroni.HandlerFunc(middleware.CheckCache), negroni.HandlerFunc(middleware.Authenticated), negroni.NewLogger()},
        Handler:    handlers.APIInfo,
    },
}

最后,当我启动服务器时,我导入路由列表并注册它们:

for _, r := range routes {

  handler := append(r.Middleware, negroni.Wrap(r.Handler))

  router.Handle(r.Path, negroni.New(handler...)).Methods(r.Method)
}

这完美无缺。

任何想法如何只使用标准的net/http签名以及定义如下所示的中间件处理程序的方式来做到这一点:

http.Handle("/", middlewareOne(middlewareTwo(finalHandler)))

谢谢:)

2 个答案:

答案 0 :(得分:1)

func Auth(n http.Handler) http.Handler {
  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
      log.Printf("Start")
      n.ServeHTTP(w, r)
      log.Printf("End")
  })
}

func processReq(w http.ResponseWriter, r *http.Request) {
  w.Write([]byte("Success"))
}


func main() {
  handler := http.HandlerFunc(processReq)

  http.Handle("/",Auth(handler))
  http.ListenAndServe(":8000", nil)
}

可以使用http.handler

完成

答案 1 :(得分:0)

简单。您可以像这样定义每个处理程序:

// So I don't have to type it over and over...
type HTTPHandler func(w http.ResponseWriter, r *http.Request)

func Handler1(next HTTPHandler) HTTPHandler {
    return func(w http.ResponseWriter, r *http.Request){
        // Do stuff

        if next != nil {
            next(w, r)
        }
    }
}

// Handler2 ... HandlerN defined in the same basic way.

// Chaining:
http.Handle("/", Handler1(Handler2(nil)))

每个处理程序获取下一个处理程序并返回一个闭包,它可以执行任何操作并调用下一个处理程序。如果你需要很多这样的东西,写一个类似于这个的帮手可能是有意义的:

func MakeHandler(worker, next HTTPHandler) HTTPHandler {
    return func(w http.ResponseWriter, r *http.Request){
        // Maybe have to worker return an error and do standard error
        // handling here? Could simplify your code some depending on
        // what you are doing.
        worker(w, r)

        if next != nil {
            next(w, r)
        }
    }
}