gpt4 book ai didi

design-patterns - 如何将golang请求中的上下文传递给中间件

转载 作者:IT王子 更新时间:2023-10-29 01:26:27 24 4
gpt4 key购买 nike

我试图了解 Golang 1.7 中引入的上下文是如何工作的,以及将它传递给中间件和 HandlerFunc 的合适方法是什么。上下文是否应该在主函数中初始化并传递给 checkAuth 函数?以及如何将其传递给 HanlderServeHTTP 函数?我读了Go concurrency patternsHow to use Context但我很难使这些模式适应我的代码。

func checkAuth(authToken string) util.Middleware {
return func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Auth") != authToken {
util.SendError(w, "...", http.StatusForbidden, false)
return
}
h.ServeHTTP(w, r)
})
}
}

// Handler is a struct
type Handler struct {
...
...
}

// ServeHTTP is the handler response to an HTTP request
func (h *HandlerW) ServeHTTP(w http.ResponseWriter, r *http.Request) {
decoder := json.NewDecoder(r.Body)

// decode request / context and get params
var p params
err := decoder.Decode(&p)
if err != nil {
...
return
}

// perform GET request and pass context
...


}


func main() {
router := mux.NewRouter()

// How to pass context to authCheck?
authToken, ok := getAuthToken()
if !ok {
panic("...")
}
authCheck := checkAuth(authToken)

// initialize middleware handlers
h := Handler{
...
}

// chain middleware handlers and pass context
router.Handle("/hello", util.UseMiddleware(authCheck, Handler, ...))
}

最佳答案

如果您查看 first example at that Go Concurrency Patterns blog post ,您会注意到它们是从 Background 上下文“派生”它们的上下文。结合 Request 对象上的 ContextWithContext 方法,可以满足您的需求。

我刚刚弄明白了(这不是我第一次阅读这些文档);当您“导出”一个上下文时,您正在通过一次更改创建另一个上下文。我已经包装了 http.Handler(实际上是使用 httprouter.Handle)。 Request.Context 的妙处在于它永远不会返回 nil;如果没有创建其他上下文,则返回后台上下文。

要指定超时,在您的处理程序中(就在您的“//执行 GET 请求”评论上方),您可以执行以下操作:

ctx, cancel := context.WithTimeout(r.Context(), time.Duration(60*time.Second))
defer cancel()
r = r.WithContext(ctx)

第一行创建上下文并为您提供取消 Hook ,您可以推迟;一旦请求得到服务,执行此延迟调用(第 2 行)时,任何派生上下文(也就是您添加变量的上下文)都将被取消。最后,第 3 行替换了请求,该请求现在包含更新后的上下文。

在您的授权检查器中,一旦确定用户有效,就可以在调用 ServeHTTP 之前将用户信息添加到上下文中。上下文的键不能使用内置类型,但您可以创建一个新类型,它只是内置类型的别名。为您的键值定义常量也是一个好主意。一个例子:

type ContextKey string

const ContextUserKey ContextKey = "user"

// Then, just above your call to ServeHTTP...

ctx := context.WithValue(r.Context(), ContextUserKey, "theuser")
h.ServeHTTP(w, r.WithContext(ctx))

这会将现在两次派生的上下文(现在具有超时用户 ID)传递给处理程序。

最后,拼图的最后一 block - 如何从处理程序中获取用户 ID。这是最直接的部分;我们只需对从请求的 Context 方法返回的值使用 Value 方法。类型是 interface{},因此如果您想将其视为字符串(如本例所示),则需要类型断言。

user := r.Context().Value(ContextUserKey)
doSomethingForThisUser(user.(string))

您不限于对每种方法进行一次更改;只要你继续派生相同的上下文,一旦请求被服务,它就会被清理干净,当最初派生的上下文(在这个例子中,我们指定超时的那个)在延迟 cancel() 调用触发。

关于design-patterns - 如何将golang请求中的上下文传递给中间件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39946583/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com