Golang中API Handler无法访问中间件Context值的问题
问题:中间件存入Context的用户ID无法在Handler中获取
需求是在Auth中间件验证JWT后,将用户ID存入请求Context并传递给后续API Handler使用。目前中间件内部能正常获取Context中的值,但Handler中始终无法访问该值。
关键代码
路由代码
addProductDistHandler := middlewares.Auth(client, log) r.Handle("/add-product-distributor", addProductDistHandler(http.HandlerFunc(handlers.AddProductDist(log, client))))
Auth中间件代码
logger.InfoLog.Printf("user.ObjectID %T",user.ObjectID) logger.InfoLog.Printf("user.ObjectID %v",user.ObjectID) // Add user ID to request context ctx := context.WithValue(r.Context(), userIDKey, user.ObjectID) r = r.WithContext(ctx) logger.InfoLog.Printf("context : %T => %v",ctx,ctx) distID, _ := r.Context().Value(userIDKey).(string) logger.InfoLog.Printf("distID : %s",distID) // Call the next handler next.ServeHTTP(w, r)
Handler代码
distID, ok := r.Context().Value(userIDKey).(string) if !ok { logger.InfoLog.Println("userIDKey is not of type string or is nil") helpers.EncodeJSON(w, http.StatusInternalServerError, "userIDKey is not of type string or is nil", nil) return }
日志信息
INFO 2024/06/21 23:36:46 cookie retrieved successfully INFO 2024/06/21 23:36:46 ObjectID("66757f98606b94271a05cd24") INFO 2024/06/21 23:36:46 user.ObjectID string INFO 2024/06/21 23:36:46 user.ObjectID 66757f98606b94271a05cd24 INFO 2024/06/21 23:36:46 context : *context.valueCtx => context.Background.WithValue(type *http.contextKey, val <not Stringer>).WithValue(type *http.contextKey, val [::1]:8000).WithCancel.WithCancel.WithValue(type mux.contextKey, val <not Stringer>).WithValue(type mux.contextKey, val <not Stringer>).WithValue(type middlewares.contextKey, val 66757f98606b94271a05cd24) INFO 2024/06/21 23:36:46 distID : 66757f98606b94271a05cd24 INFO 2024/06/21 23:36:46 userIDKey is not of type string or is nil
解决方案
问题核心是**userIDKey的定义不统一**:Go中context.WithValue的键是基于「类型+值」来区分的,如果中间件和Handler各自在不同包中定义了同名的contextKey类型,这两个类型属于不同的标识,导致Handler无法通过自己的userIDKey取出中间件存入的值。
修复步骤:
- 在中间件包中导出统一的
UserIDKey常量:
package middlewares type contextKey string // 导出该键,供其他包直接引用 const UserIDKey contextKey = "userID"
- 在Handler中直接使用中间件包导出的
UserIDKey取值:
import "your-project-path/middlewares" // ... distID, ok := r.Context().Value(middlewares.UserIDKey).(string) if !ok { // 错误处理逻辑 }
- 额外校验:确保存入Context的值类型与取出时断言的类型一致。从日志看,中间件中
user.ObjectID是string类型,Handler中断言为string是正确的;如果实际是primitive.ObjectID,则要对应调整断言类型。
内容的提问来源于stack exchange,提问作者user25606885
相关产品推荐
相关产品推荐

