2017-02-14 29 views
0

我的基本main設置:請求上下文中嵌套大猩猩丟失Subrouter

muxRouter := mux.NewRouter() 

v1Router.Router(muxRouter.PathPrefix("/v1").Subrouter()) 

http.Handle("/", muxRouter) 


n := negroni.Classic() 
n.Use(negroni.HandlerFunc(apiRouter.Middleware)) 
n.UseHandler(muxRouter) 

s := &http.Server{ 
    Addr:   ":6060", 
    Handler:  n, 
    ReadTimeout: 10 * time.Second, 
    WriteTimeout: 10 * time.Second, 
    MaxHeaderBytes: 1 << 20, 
} 
log.Fatal(s.ListenAndServe()) 

我已經設置了以下方面的apiRouter.Middleware內部:內

context.Set(req, helperKeys.DomainName, "some-value") 

然而,在一些handlerFunc v1Router.Router當試圖Get上下文的值時,結果爲零:

domain := context.Get(req, helperKeys.DomainName) 
fmt.Println("DomainName", domain) 

打印:DomainName <nil>

我知道Set方法是將其設置在apiRouter.Middleware將返回正確的字符串值後所獲得的價值立即糾正。

回答

0

我結束了使用內置ContextGo 1.7的:

context.Set(req, helperKeys.DomainName, "some-value") 

// Replaced with: 

ctx := req.Context() 
ctx = context.WithValue(ctx, helperKeys.DomainName, "some-value") 
req = req.WithContext(ctx) 

domain := context.Get(req, helperKeys.DomainName) 

// Replaced with: 

domain := req.Context().Value(helperKeys.DomainName).(string) 
+0

請使用類型轉換的較長版本'(域,確定:= REQ .Context()。Value(...)' 如果存在像從未設置的值這樣的問題,它將爲您節省很多麻煩,我還會爲上下文值和未導出的鍵使用自定義getters/setters。其中更安全的實踐和沒有更多的代碼 – joncalhoun

0

根據您的回答,它看起來像你想存儲在上下文數據庫。我不會建議這樣做。相反,嘗試這樣的事:

type Something struct { 
    DB *sql.DB // or some other DB object 
} 

func (s *Something) CreateUser(w http.ResponseWriter, r *http.Request) { 
    // use s.DB to access the database 
    fmt.Fprintln(w, "Created a user...") 
} 

func main() { 
    db := ... 
    s := Something{db} 
    http.HandleFunc("/", s.CreateUser) 
    // ... everything else is pretty much like normal. 
} 

這給你的處理程序訪問數據庫,而不必把它放在上下文每一次。上下文值應該保留給你直到運行時才能設置的事情。例如,特定於該Web請求的請求ID。超出請求範圍的東西通常不屬於這個類別,並且您的數據庫連接將超出請求。

如果你確實需要上下文值,你應該:被輸入

    1. 使用getter和setter「包應該定義鍵爲取消導出類型,以避免衝突。」 - From the Go source code

    這方面的一個例子如下所示,我在一般在this blog post詳細討論的上下文值:

    type userCtxKeyType string 
    
    const userCtxKey userCtxKeyType = "user" 
    
    func WithUser(ctx context.Context, user *User) context.Context { 
        return context.WithValue(ctx, userCtxKey, user) 
    } 
    
    func GetUser(ctx context.Context) *User { 
        user, ok := ctx.Value(userCtxKey).(*User) 
        if !ok { 
        // Log this issue 
        return nil 
        } 
        return user 
    } 
    
  • +0

    嘿謝謝你的擡頭,但我實際上並沒有存儲數據庫,我只是storin g連接會話的副本到數據庫。我在主函數中連接到數據庫,並且只在每個請求的上下文中存儲會話的副本 – borislemke

    +0

    這仍然通常被忽視 - 數據庫連接的副本根本不是特定於請求的,並且可能很容易通過我在這裏展示的第一種方法訪問,從長遠來看這更安全。 從數據庫連接創建的事務可能存儲的更多信息,只要請求處於活動狀態,該事務將只存活。 也就是說,我希望這樣做能夠加快速度。我只是想,我會讓你知道,隨着你的應用程序的增長,更容易維護和調試,有更好的方法來處理這個問題。 – joncalhoun