2015-07-19 60 views
2

我正在设计我的处理程序来返回一个http.Handler。这里是我的处理程序的设计:如何将数据从中间件传递给处理程序?

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

我中间件旨在接受http.Handler,然后调用处理程序,一旦中间件完成执行其操作。这里是我的中间件的设计:

func Middleware(next http.Handler) http.Handler { 
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 
    // Middleware operations 

    next.ServeHTTP(w, r) 
    }) 
} 

考虑我的中间件和处理程序的设计,什么是从中间件的信息传递到处理程序的正确方法?我试图从中间件传递给处理程序的信息是从请求主体解析的JSON Web标记。如果我没有将解析的JWT传递给处理程序,那么我需要在处理程序中再次解析JWT。在中间件和处理程序中解析JWT的请求主体看起来很浪费。为了防止这些信息相关,我使用带有大猩猩多路复用器的标准网络/ http库。

回答

4

类似于该问题的第一种方法是codemodus/chainDaved

包链帮助包含请求范围数据的Handler包装链组合。

它使用notion of Context,再加上一个上下文句柄:

func ctxHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) { 
    // ... 

    if s, ok := getMyString(ctx); ok { 
     // s = "Send this down the line." 
    } 

    // ... 
} 

另一种方法:你可以在 “Custom Handlers and Avoiding Globals in Go Web Applications” 看看,通过Matt Silverlock (elithrar)。 (full example here

这个想法是在包含相关上下文的类型上定义ServeHTTP

// We've turned our original appHandler into a struct with two fields: 
// - A function type similar to our original handler type (but that now takes an *appContext) 
// - An embedded field of type *appContext 
type appHandler struct { 
    *appContext 
    h func(*appContext, http.ResponseWriter, *http.Request) (int, error) 
} 

// Our ServeHTTP method is mostly the same, and also has the ability to 
// access our *appContext's fields (templates, loggers, etc.) as well. 
func (ah appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 
    // Updated to pass ah.appContext as a parameter to our handler type. 
    status, err := ah.h(ah.appContext, w, r) 
    if err != nil { 
     log.Printf("HTTP %d: %q", status, err) 
     switch status { 
     case http.StatusNotFound: 
      http.NotFound(w, r) 
      // And if we wanted a friendlier error page, we can 
      // now leverage our context instance - e.g. 
      // err := ah.renderTemplate(w, "http_404.tmpl", nil) 
     case http.StatusInternalServerError: 
      http.Error(w, http.StatusText(status), status) 
     default: 
      http.Error(w, http.StatusText(status), status) 
     } 
    } 
} 

appContext结构中,您可以放入任何要传递的数据。

2

由于您已经在使用Gorilla请查看context包。

(这是不错的,如果你不想改变你的方法签名。)

import (
    "github.com/gorilla/context" 
) 

... 

func Middleware(next http.Handler) http.Handler { 
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 
     // Middleware operations 
     // Parse body/get token. 
     context.Set(r, "token", token) 

     next.ServeHTTP(w, r) 
    }) 
} 

... 

func Handler() http.Handler { 
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 
     token := context.Get(r, "token") 
    }) 
} 
0

传请求的正确方法作用域现在的数据是上下文包中的标准库。

https://golang.org/pkg/context/

你可以用request.Context访问上http.Request。

相关问题