2015-07-19 63 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。

相關問題