Golang中使用Http Context添加用户信息的方法
Golang中使用Http Context添加用户信息的方法
我正在尝试在一个中间件的 ServeHTTP http.Handler 函数中,设置一个包含用户信息的新上下文。我可以将新上下文传递给同一页面内的一个函数,并且它能正确打印出新上下文。然而,当我将其传递给下一个中间件处理器时,新的上下文值却是空的。在这个例子中,下一个中间件是一个记录日志的函数,它包装了整个请求,如下所示:
wrappedMux := NewLogger(NewEnsureAuth(NewResponseHeader(mux, “X-Launchpad-Request-Id”, uuidV2.String())))
以下是相关代码:
// 在同一文件内。
type EnsureAuth struct {
handler http.Handler
}
func doSomething(ctx context.Context) {
fmt.Printf("doSomething: myKey's value is %s\n", ctx.Value("Launchpad"))
// 输出是:"doSomething: myKey's value is {Bugs Bunny bugs@large.net}"
}
func (ea *EnsureAuth) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if authResult.Authenticated {
// 创建一个包含已认证用户信息的新请求上下文
newCtx := context.WithValue(r.Context(), "Launchpad", authResult.User)
// 使用新上下文创建一个新请求
rWithUser := r.WithContext(newCtx)
doSomething(rWithUser.Context())
r.URL.Path = "/index.html"
w.Header().Set("Content-Type", "text/html")
w.WriteHeader(http.StatusOK)
// 调用实际的处理器,传递新请求
ea.handler.ServeHTTP(w, rWithUser)
}
}
// 在另一个文件中。
func (l *Logger) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(os.Stderr, "Your User: %v", r.Context().Value("Launchpad"))
// 输出是:"Your User: <nil>"
}
非常感谢任何帮助。如果需要我提供更多细节,请告诉我。
更多关于Golang中使用Http Context添加用户信息的方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html
关于我在传递用户上下文时遇到的问题,我认为问题可能在于首次中间件调用日志处理器(用于获取请求开始时间)时,尚未拥有用户上下文。
下一个中间件对用户进行身份验证并添加用户上下文,之后我确实能够查看并打印用户上下文。然而,当其他中间件链执行完毕,我们返回到日志记录器进行实际日志记录时,用户上下文再次缺失。
我无法完全确定,但看起来日志记录中间件仍在使用原始的 HTTP 请求,尽管我能在前一个中间件的 ServeHTTP 调用请求中看到用户上下文。
如果有人能对此提供一些见解,我将不胜感激。
更多关于Golang中使用Http Context添加用户信息的方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
问题在于你修改了请求的上下文,但没有将这个修改后的请求传递给后续的中间件。在你的 EnsureAuth.ServeHTTP 方法中,你创建了 rWithUser 但随后又修改了原始请求 r 的路径,这可能导致上下文没有正确传递。
以下是修正后的代码示例:
func (ea *EnsureAuth) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if authResult.Authenticated {
// 创建包含用户信息的新上下文
newCtx := context.WithValue(r.Context(), "Launchpad", authResult.User)
// 使用新上下文创建新请求
rWithUser := r.WithContext(newCtx)
// 修改新请求的路径
rWithUser.URL.Path = "/index.html"
// 设置响应头
w.Header().Set("Content-Type", "text/html")
// 测试:在同一中间件内访问上下文
doSomething(rWithUser.Context())
// 传递修改后的请求给下一个处理器
ea.handler.ServeHTTP(w, rWithUser)
} else {
// 处理未认证的情况
w.WriteHeader(http.StatusUnauthorized)
}
}
关键点:
- 所有对请求的修改(包括路径修改)都应该在
rWithUser上进行,而不是原始请求r - 确保将
rWithUser传递给ea.handler.ServeHTTP() - 在日志中间件中,上下文值应该能正常访问:
func (l *Logger) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// 现在应该能正确获取到用户信息
if user := r.Context().Value("Launchpad"); user != nil {
fmt.Fprintf(os.Stderr, "Your User: %v\n", user)
} else {
fmt.Fprintf(os.Stderr, "No user found in context\n")
}
// 继续处理请求
l.handler.ServeHTTP(w, r)
}
这样修改后,上下文值应该能在整个中间件链中正确传递。

