作为一个工作8年的老程序员通知你:浏览源码和查看官网文档,是解决问题最高效的方法。不信你来看,这个困扰了读者半天的问题我查了源码和文档后霎时解决。
前言
上周五有位读者私信我一个问题,说困扰了他半天,钻研了一个上午也没搞明确。
是一位运维转Go的敌人,最近有不少运维、测试、甚至Java、PHP转Go的敌人加我。
这个问题并不是喋喋不休就能讲清楚的,我就整顿了一篇文章给他。
高兴
正如上图所示,反馈特地的好,更文的高兴又找到了,我把这个问题和解答又好好整顿了一下,分享给大家,心愿对大家有帮忙.
也分享一下我作为一个工作8年的老程,解决问题的心得:
浏览源码和查看官网文档,是解决问题最高效的方法。
发问
在gofame框架的demo案例中,如下图所示:
- 为什么左侧路由绑定这里没有向controller中传入context的值,在controller中却能取到值?
- 如何赋值和接管context?
先说论断
- 对于
ctx context.Context
上下文,Server组件会主动从申请中获取并传递给接口办法,申明并初始化了context初始值为context.Background()
- 能够通过GetCtx、SetCtx、GetCtxVar、SetCtxVar这些办法轻松的为context赋值和取值
- 通过示例代码轻松可知:咱们能够通过
ghttp.Request
实例轻松的操作context。
解答
问题1. 为什么左侧路由绑定这里没有向controller中传入context的值,在controller中却能取到值?
先说论断:对于ctx context.Context
上下文,Server组件会主动从申请中获取并传递给接口办法。
要害代码是上图中的s := g.Server()
:
追踪一下它的源码能够发现:申明并初始化了ctx的初始值:context.Background()
再带大家看一下context.Background()
的源码和正文。
// Background returns a non-nil, empty Context. It is never canceled, has no// values, and has no deadline. It is typically used by the main function,// initialization, and tests, and as the top-level Context for incoming// requests.func Background() Context { return background}
咱们能够发现这里返回了一个non-nil, empty Context
问题2. 如何赋值和接管context?
在GoFrame框架中,官网举荐的正是应用Context上下文对象来解决流程共享的上下文变量,甚至将该对象进一步传递到依赖的各个模块办法中。
该Context对象类型实现了规范库的context.Context接口,该接口往往会作为模块间调用办法的第一个参数,该接口参数也是Golang官网举荐的在模块间传递上下文变量的举荐形式。
办法列表:
func (r *Request) GetCtx() context.Contextfunc (r *Request) SetCtx(ctx context.Context)func (r *Request) GetCtxVar(key interface{}, def ...interface{}) *gvar.Varfunc (r *Request) SetCtxVar(key interface{}, value interface{})
简要阐明:
- GetCtx办法用于获取以后的context.Context对象,作用同Context办法。
- SetCtx办法用于设置自定义的context.Context上下文对象。
- GetCtxVar办法用于获取上下文变量,并可给定当该变量不存在时的默认值。
- SetCtxVar办法用于设置上下文变量。
应用示例
示例1,SetCtxVar/GetCtxVar
package mainimport ( "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/ghttp")const ( TraceIdName = "trace-id")func main() { s := g.Server() s.Group("/", func(group *ghttp.RouterGroup) { group.Middleware(func(r *ghttp.Request) { //向context中赋值 r.SetCtxVar(TraceIdName, "1234567890abcd") r.Middleware.Next() }) group.ALL("/", func(r *ghttp.Request) { //从context中取值 r.Response.Write(r.GetCtxVar(TraceIdName)) }) }) s.SetPort(8199) s.Run()}
能够看到:咱们能够通过SetCtxVar和GetCtxVar来设置和获取自定义的变量,该变量生命周期仅限于以后申请流程。
执行后,拜访 http://127.0.0.1:8199/ ,页面输入内容为:1234567890abcd
示例2,SetCtx
SetCtx办法罕用于中间件中整合一些第三方的组件,例如第三方的链路跟踪组件等等。
为简化示例,这里咱们将下面的例子通过SetCtx办法来革新一下来做演示。
package mainimport ( "context" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/ghttp")const ( TraceIdName = "trace-id")func main() { s := g.Server() s.Group("/", func(group *ghttp.RouterGroup) { group.Middleware(func(r *ghttp.Request) { ctx := context.WithValue(r.Context(), TraceIdName, "1234567890abcd") r.SetCtx(ctx) r.Middleware.Next() }) group.ALL("/", func(r *ghttp.Request) { //看到这里的示例代码,更能解答问题1,通过ghttp.Request能够轻松取得上下文对象 r.Response.Write(r.Context().Value(TraceIdName)) // 也能够应用 // r.Response.Write(r.GetCtxVar(TraceIdName)) }) }) s.SetPort(8199) s.Run()}
执行后,拜访 http://127.0.0.1:8199/ ,页面输入内容为:1234567890abcd
总结
通过下面的示例,咱们能更好的了解这位星友提出的困惑:
- 对于
ctx context.Context
上下文,Server组件会主动从申请中获取并传递给接口办法,申明并初始化了context初始值为context.Background()
- 能够通过GetCtx、SetCtx、GetCtxVar、SetCtxVar这些办法轻松的为context赋值和取值
- 通过示例代码轻松可知:咱们能够通过
ghttp.Request
实例轻松的操作context。
参考链接
- 路由注册-标准路由
- 申请输出-Context
一起提高
如果你感觉这篇文章不错,欢送点赞,评论。
我的思否声望什么时候能到200呀!?