作為一個工作8年的老程序員告訴你:閱讀源碼和查看官方文檔,是解決問題最高效的辦法。不信你來看,這個困擾了讀者半天的問題我查了源碼和文檔后瞬間解決。
前言
上周五有位讀者私信我一個問題,說困擾了他半天,研究了一個上午也沒搞明白。
是一位運維轉(zhuǎn)Go的朋友,最近有不少運維、測試、甚至Java、PHP轉(zhuǎn)Go的朋友加我。
這個問題并不是三言兩語就能講清楚的,我就整理了一篇文章給他。
快樂
正如上圖所示,反饋特別的好,更文的快樂又找到了,我把這個問題和解答又好好整理了一下,分享給大家,希望對大家有幫助.
也分享一下我作為一個工作8年的老程,解決問題的心得:
閱讀源碼和查看官方文檔,是解決問題最高效的辦法。
提問
在gofame框架的demo案例中,如下圖所示:
- 為什么左側(cè)路由綁定這里沒有向controller中傳入context的值,在controller中卻能取到值?
- 如何賦值和接收context?
先說結(jié)論
- 關(guān)于
ctx context.Context
上下文,Server組件會自動從請求中獲取并傳遞給接口方法,聲明并初始化了context初始值為context.Background()
- 可以通過GetCtx、SetCtx、GetCtxVar、SetCtxVar這些方法輕松的為context賦值和取值
- 通過示例代碼輕松可知:我們可以通過
ghttp.Request
實例輕松的操作context。
解答
問題1. 為什么左側(cè)路由綁定這里沒有向controller中傳入context的值,在controller中卻能取到值?
先說結(jié)論:關(guān)于ctx context.Context
上下文,Server組件會自動從請求中獲取并傳遞給接口方法。
關(guān)鍵代碼是上圖中的s := g.Server()
:
追蹤一下它的源碼可以發(fā)現(xiàn):聲明并初始化了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
}
我們可以發(fā)現(xiàn)這里返回了一個non-nil, empty Context
問題2. 如何賦值和接收context?
在GoFrame框架中,官方推薦的正是使用Context上下文對象來處理流程共享的上下文變量,甚至將該對象進一步傳遞到依賴的各個模塊方法中。
該Context對象類型實現(xiàn)了標準庫的context.Context接口,該接口往往會作為模塊間調(diào)用方法的第一個參數(shù),該接口參數(shù)也是Golang官方推薦的在模塊間傳遞上下文變量的推薦方式。
方法列表:
func (r *Request) GetCtx() context.Context
func (r *Request) SetCtx(ctx context.Context)
func (r *Request) GetCtxVar(key interface{}, def ...interface{}) *gvar.Var
func (r *Request) SetCtxVar(key interface{}, value interface{})
簡要說明:
- GetCtx方法用于獲取當(dāng)前的context.Context對象,作用同Context方法。
- SetCtx方法用于設(shè)置自定義的context.Context上下文對象。
- GetCtxVar方法用于獲取上下文變量,并可給定當(dāng)該變量不存在時的默認值。
- SetCtxVar方法用于設(shè)置上下文變量。
使用示例
示例1,SetCtxVar/GetCtxVar
package main
import (
"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來設(shè)置和獲取自定義的變量,該變量生命周期僅限于當(dāng)前請求流程。
執(zhí)行后,訪問 http://127.0.0.1:8199/ ,頁面輸出內(nèi)容為:1234567890abcd
示例2,SetCtx
SetCtx方法常用于中間件中整合一些第三方的組件,例如第三方的鏈路跟蹤組件等等。
為簡化示例,這里我們將上面的例子通過SetCtx方法來改造一下來做演示。
package main
import (
"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()
}
執(zhí)行后,訪問 http://127.0.0.1:8199/ ,頁面輸出內(nèi)容為:1234567890abcd
總結(jié)
通過上面的示例,我們能更好的理解這位星友提出的困惑:
- 關(guān)于
ctx context.Context
上下文,Server組件會自動從請求中獲取并傳遞給接口方法,聲明并初始化了context初始值為context.Background()
- 可以通過GetCtx、SetCtx、GetCtxVar、SetCtxVar這些方法輕松的為context賦值和取值
- 通過示例代碼輕松可知:我們可以通過
ghttp.Request
實例輕松的操作context。
參考鏈接
-
路由注冊-規(guī)范路由
-
請求輸入-Context
一起學(xué)習(xí)
文章來源:http://www.zghlxwxcb.cn/news/detail-458013.html
歡迎關(guān)注下方公眾號:程序員升職加薪之旅,也歡迎 加我好友 一起學(xué)習(xí)文章來源地址http://www.zghlxwxcb.cn/news/detail-458013.html
到了這里,關(guān)于閱讀源碼和查看官方文檔,是解決問題最高效的辦法。的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!