从切片中嵌套函数

huangapple go评论108阅读模式
英文:

Nest Functions From Slice

问题

我正在构建一个支持各种中间件函数的 Go Web 应用程序,用于处理路由。我尽量使用 net/http,想知道如何在不使用像 negroni 这样的中间件库的情况下实现这一点。

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

我可以使用 negroni 简单地实现这一点,定义如下结构体:

  1. // Route ..
  2. type Route struct {
  3. Method string
  4. Path string
  5. Middleware []negroni.Handler
  6. Handler http.HandlerFunc
  7. }

然后像这样定义一个路由:

  1. var commonRoutes = []Route{
  2. {
  3. Method: "GET",
  4. Path: "/info",
  5. Middleware: []negroni.Handler{negroni.HandlerFunc(middleware.CheckCache), negroni.HandlerFunc(middleware.Authenticated), negroni.NewLogger()},
  6. Handler: handlers.APIInfo,
  7. },
  8. }

最后,当我启动服务器时,我导入路由列表并进行注册,像这样:

  1. for _, r := range routes {
  2. handler := append(r.Middleware, negroni.Wrap(r.Handler))
  3. router.Handle(r.Path, negroni.New(handler...)).Methods(r.Method)
  4. }

这样可以完美地工作。

有没有办法只使用标准的 net/http 签名和定义中间件处理程序的方式来实现这一点呢?

谢谢 从切片中嵌套函数

英文:

I am building a Go web application that supports various middleware functions when handling routing. I'm trying to stick to net/http as much as possible and was wondering how I might accomplish this without using middleware libraries like negroni.

Essentially what I would like to do is to be able to provide a slice of middleware functions, say one for logging, one for checking for a valid JWT, and then finally the handler to handle the request.

I am able to do this with negroni fairly simply by defining the following struct:

  1. // Route ..
  2. type Route struct {
  3. Method string
  4. Path string
  5. Middleware []negroni.Handler
  6. Handler http.HandlerFunc
  7. }

and then defining a route like:

  1. var commonRoutes = []Route{
  2. {
  3. Method: "GET",
  4. Path: "/info",
  5. Middleware: []negroni.Handler{negroni.HandlerFunc(middleware.CheckCache), negroni.HandlerFunc(middleware.Authenticated), negroni.NewLogger()},
  6. Handler: handlers.APIInfo,
  7. },
  8. }

Finally when I boot up my server, I import the list of routes and register them like so:

  1. for _, r := range routes {
  2. handler := append(r.Middleware, negroni.Wrap(r.Handler))
  3. router.Handle(r.Path, negroni.New(handler...)).Methods(r.Method)
  4. }

And this works perfectly.

Any idea how I might be able to do this with just the standard net/http signature and way of defining middleware handlers that look like this:

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

Thank you 从切片中嵌套函数

答案1

得分: 1

可以使用http.Handler来完成翻译:

  1. func Auth(n http.Handler) http.Handler {
  2. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  3. log.Printf("开始")
  4. n.ServeHTTP(w, r)
  5. log.Printf("结束")
  6. })
  7. }
  8. func processReq(w http.ResponseWriter, r *http.Request) {
  9. w.Write([]byte("成功"))
  10. }
  11. func main() {
  12. handler := http.HandlerFunc(processReq)
  13. http.Handle("/",Auth(handler))
  14. http.ListenAndServe(":8000", nil)
  15. }

希望这可以帮助到你!

英文:
  1. func Auth(n http.Handler) http.Handler {
  2. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  3. log.Printf("Start")
  4. n.ServeHTTP(w, r)
  5. log.Printf("End")
  6. })
  7. }
  8. func processReq(w http.ResponseWriter, r *http.Request) {
  9. w.Write([]byte("Success"))
  10. }
  11. func main() {
  12. handler := http.HandlerFunc(processReq)
  13. http.Handle("/",Auth(handler))
  14. http.ListenAndServe(":8000", nil)
  15. }

can be done using http.handler

答案2

得分: 0

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

  1. // 为了不重复输入...
  2. type HTTPHandler func(w http.ResponseWriter, r *http.Request)
  3. func Handler1(next HTTPHandler) HTTPHandler {
  4. return func(w http.ResponseWriter, r *http.Request){
  5. // 做一些事情
  6. if next != nil {
  7. next(w, r)
  8. }
  9. }
  10. }
  11. // Handler2 ... HandlerN 以相同的基本方式定义。
  12. // 链接:
  13. http.Handle("/", Handler1(Handler2(nil)))

每个处理程序接受下一个处理程序,并返回一个闭包,该闭包执行你想要的操作,并调用下一个处理程序。如果你需要很多这样的处理程序,可能有必要编写一个类似于以下示例的辅助函数:

  1. func MakeHandler(worker, next HTTPHandler) HTTPHandler {
  2. return func(w http.ResponseWriter, r *http.Request){
  3. // 可能需要让 worker 返回一个错误,并在这里进行标准错误处理?
  4. // 根据你的具体情况,这可能会简化你的代码。
  5. worker(w, r)
  6. if next != nil {
  7. next(w, r)
  8. }
  9. }
  10. }
英文:

Simple. You define each handler like so:

  1. // So I don't have to type it over and over...
  2. type HTTPHandler func(w http.ResponseWriter, r *http.Request)
  3. func Handler1(next HTTPHandler) HTTPHandler {
  4. return func(w http.ResponseWriter, r *http.Request){
  5. // Do stuff
  6. if next != nil {
  7. next(w, r)
  8. }
  9. }
  10. }
  11. // Handler2 ... HandlerN defined in the same basic way.
  12. // Chaining:
  13. http.Handle("/", Handler1(Handler2(nil)))

Each handler takes the next handler and returns a closure that does whatever you want plus calling the next handler. If you need lots of these it may make sense to write a helper similar to this one:

  1. func MakeHandler(worker, next HTTPHandler) HTTPHandler {
  2. return func(w http.ResponseWriter, r *http.Request){
  3. // Maybe have to worker return an error and do standard error
  4. // handling here? Could simplify your code some depending on
  5. // what you are doing.
  6. worker(w, r)
  7. if next != nil {
  8. next(w, r)
  9. }
  10. }
  11. }

huangapple
  • 本文由 发表于 2017年9月19日 13:46:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/46292705.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定