使用Echo v4框架无法获取请求传入的Context的问题咨询
问题说明
用http.NewRequestWithContext(ctx, method, url, payload)创建携带自定义Context的请求后,Gin框架通过c.Request.Context()能直接拿到传入的Context,但Echo/v4里用c.Request().Context()拿到的Context指针和传入的不一致,需要正确获取原始Context的内容。
原因分析
Echo在处理请求时,会基于原始请求的Context创建新的子Context(添加框架自身的上下文数据),所以直接对比指针会不一样,但原始Context里的键值对会被继承保留。
解决方案
1. 直接获取自定义键值
如果你的Context里存了自定义数据(比如用context.WithValue设置的),直接通过c.Request().Context().Value(你的自定义键)就能拿到,因为Context的链式继承会保留所有父Context的值。
示例:
// 发送请求时构建带自定义数据的Context ctx := context.WithValue(context.Background(), "user_id", 123) req, _ := http.NewRequestWithContext(ctx, "GET", "/api/test", nil) // Echo Handler中获取自定义值 userId := c.Request().Context().Value("user_id")
2. 检查中间件是否修改了请求
如果你的Echo应用有自定义中间件,检查是否存在c.SetRequest(req.WithContext(newCtx))这类完全替换请求Context的代码——这种操作会覆盖原始Context,需要调整中间件逻辑,确保基于原始Context创建新的子Context,而非直接替换。
3. 手动保存原始Context到Echo上下文
如果需要严格保留原始Context的引用,可以在全局中间件里把它存入Echo上下文:
e.Use(func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { // 将原始请求Context存入Echo上下文 c.Set("original_request_ctx", c.Request().Context()) return next(c) } }) // 在Handler中取出 originalCtx := c.Get("original_request_ctx").(context.Context)
注意:其实c.Request().Context()本身就是原始Context的子Context,只要没有被中间件完全替换,里面的所有值都能正常获取,一般无需额外保存,除非你需要严格对比指针。
内容的提问来源于stack exchange,提问作者Jacob Wilfridovich

