在我的日志(log)中间件(链中的第一个)中,我需要访问在链的更下游的某个身份验证中间件中编写的一些上下文,并且只有在执行处理程序本身之后才能访问.
Side note: The logging middleware needs to be called first since I need to log the duration of the request including the time spend in middleware. Also the auth middleware is able to abort a request when permissions are not sufficient. in that case I need to log the failed request as well.个
我的问题是,从http.Request
指针读取上下文不会返回我预期的身份验证数据.请参见下面的示例:
package main
import (
"context"
"fmt"
"net/http"
"time"
)
const (
contextKeyUsername = "username"
)
func authMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
ctx = context.WithValue(ctx, contextKeyUsername, "user123")
next.ServeHTTP(w, r.WithContext(ctx))
})
}
func logMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func(start time.Time) {
ctx := r.Context()
username := ctx.Value(contextKeyUsername)
if username != nil {
fmt.Printf("user %s has accessed %s, took %d\n", username,
r.URL.Path, time.Since(start).Milliseconds())
} else {
fmt.Printf("annonyous has accessed %s, took %d\n",
r.URL.Path, time.Since(start).Milliseconds())
}
}(time.Now())
next.ServeHTTP(w, r)
})
}
func welcome(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
username := ctx.Value(contextKeyUsername)
if username != nil {
fmt.Fprintf(w, fmt.Sprintf("hello %s", username.(string)))
} else {
fmt.Fprintf(w, "hello")
}
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/welcome", welcome)
chain := logMiddleware(authMiddleware(mux))
http.ListenAndServe(":5050", chain)
}
尽管对127.0.0.1:5050/welcome
的GET请求确实返回预期的字符串hello user123
,但日志(log)的输出是:
annonyous has accessed /welcome, took 0
因为请求是作为指针传递的,所以我本以为在执行延迟时,上下文将包含预期的username
值.
我错过了什么吗?