最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

優(yōu)雅使用GoFrame共享變量Context示例詳解

 更新時(shí)間:2022年06月30日 08:58:11   作者:王中陽(yáng)Go  
這篇文章主要為大家介紹了優(yōu)雅使用GoFrame共享變量Context示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言摘要

昨天和同事merge代碼又遇到了很多沖突,發(fā)現(xiàn)之前有些方法寫的參數(shù)不規(guī)范,沒(méi)有傳入Context,不方便進(jìn)行鏈路追蹤。他在review項(xiàng)目代碼,基本把項(xiàng)目中的方法都加了Context參數(shù)。

今天就為大家介紹一下Context的使用,告訴大家Context是什么?怎么用?為什么要用Context以及使用中的小技巧和注意問(wèn)題。

Context是什么?

Context指的是標(biāo)準(zhǔn)庫(kù)的context.Context,是一個(gè)接口對(duì)象,常用于異步IO控制以及上下文流程變量的傳遞。

本文將要介紹的是Context如何優(yōu)雅的在業(yè)務(wù)流程中進(jìn)行變量的傳遞,以及為什么需要要進(jìn)行變量的傳遞。

為什么需要Context?

Go的執(zhí)行流程中,特別是HTTP/RPC執(zhí)行流程中,不存在”全局變量”獲取請(qǐng)求參數(shù)的方式,只有通過(guò)上下文Context變量傳遞到后續(xù)流程的方法中。

Context是如何實(shí)現(xiàn)共享變量的?

Context上下文變量即包含了所有需要傳遞的共享變量。

并且該Context中的共享變量是事先約定的,并且往往存儲(chǔ)為對(duì)象指針形式。

如何使用?

通過(guò)Context上下文共享變量非常簡(jiǎn)單,下面通過(guò)示例帶大家了解一下如何傳遞和使用通用的共享變量。

一、結(jié)構(gòu)定義

上下文對(duì)象中往往存儲(chǔ)一些需要共享的變量,這些變量通常使用結(jié)構(gòu)化的對(duì)象來(lái)存儲(chǔ),以方便維護(hù)。

例如,我們?cè)?code>model定義一個(gè)上下文中的共享變量:

const (
	// 上下文變量存儲(chǔ)鍵名,前后端系統(tǒng)共享
	ContextKey = "ContextKey"
)
// 請(qǐng)求上下文結(jié)構(gòu)
type Context struct {
	Session *ghttp.Session // 當(dāng)前Session管理對(duì)象
	User    *ContextUser   // 上下文用戶信息
	Data    g.Map          // 自定KV變量,業(yè)務(wù)模塊根據(jù)需要設(shè)置,不固定
}
// 請(qǐng)求上下文中的用戶信息
type ContextUser struct {
	Id       uint   // 用戶ID
	Passport string // 用戶賬號(hào)
	Nickname string // 用戶名稱
	Avatar   string // 用戶頭像
}

介紹

model.ContextKey常量表示存儲(chǔ)在context.Context上下文變量中的鍵名,該鍵名用于從傳遞的context.Context變量中存儲(chǔ)/獲取業(yè)務(wù)自定義的共享變量。

model.Context結(jié)構(gòu)體中的Session表示當(dāng)前請(qǐng)求的Session對(duì)象,在GoFrame框架中每個(gè)HTTP請(qǐng)求對(duì)象中都會(huì)有一個(gè)空的Session對(duì)象,該對(duì)象采用了懶初始化設(shè)計(jì),只有在真正執(zhí)行讀寫操作時(shí)才會(huì)初始化。

model.Context結(jié)構(gòu)體中的User表示當(dāng)前登錄的用戶基本信息,只有在用戶登錄后才有數(shù)據(jù),否則是nil。

model.Context結(jié)構(gòu)體中的Data屬性用于存儲(chǔ)自定義的KV變量,因此一般來(lái)說(shuō)開發(fā)者無(wú)需再往context.Context上下文變量中增加自定義的鍵值對(duì),而是直接使用model.``Context對(duì)象的這個(gè)Data屬性即可。

二、邏輯封裝

由于該上下文對(duì)象也是和業(yè)務(wù)邏輯相關(guān)的,因此我們需要通過(guò)service對(duì)象將上下文變量封裝起來(lái)以方便其他模塊使用。

// 上下文管理服務(wù)
var Context = new(contextService)
type contextService struct{}
// 初始化上下文對(duì)象指針到上下文對(duì)象中,以便后續(xù)的請(qǐng)求流程中可以修改。
func (s *contextService) Init(r *ghttp.Request, customCtx *model.Context) {
	r.SetCtxVar(model.ContextKey, customCtx)
}
// 獲得上下文變量,如果沒(méi)有設(shè)置,那么返回nil
func (s *contextService) Get(ctx context.Context) *model.Context {
	value := ctx.Value(model.ContextKey)
	if value == nil {
		return nil
	}
	if localCtx, ok := value.(*model.Context); ok {
		return localCtx
	}
	return nil
}
// 將上下文信息設(shè)置到上下文請(qǐng)求中,注意是完整覆蓋
func (s *contextService) SetUser(ctx context.Context, ctxUser *model.ContextUser) {
	s.Get(ctx).User = ctxUser
}

Tips

在架構(gòu)設(shè)計(jì)中,在哪個(gè)場(chǎng)景下設(shè)置Context是非常關(guān)鍵的。

上下文的變量必須在請(qǐng)求一開始便注入到請(qǐng)求流程中,以便于其他方法調(diào)用,所以在中間件中來(lái)實(shí)現(xiàn)是非常優(yōu)雅的選擇。

我們來(lái)看下面的介紹:

三、上下文變量注入

HTTP請(qǐng)求中我們可以使用GoFrame的中間件來(lái)實(shí)現(xiàn)。

GRPC請(qǐng)求中我們也可以使用攔截器來(lái)實(shí)現(xiàn)。

service層的middleware管理對(duì)象中,我們可以這樣來(lái)定義:

// 自定義上下文對(duì)象
func (s *middlewareService) Ctx(r *ghttp.Request) {
	// 初始化,務(wù)必最開始執(zhí)行
	customCtx := &model.Context{
		Session: r.Session,
		Data:    make(g.Map),
	}
	service.Context.Init(r, customCtx)
	if userEntity := Session.GetUser(r.Context()); userEntity != nil {
		customCtx.User = &model.ContextUser{
			Id:       userEntity.Id,
			Passport: userEntity.Passport,
			Nickname: userEntity.Nickname,
			Avatar:   userEntity.Avatar,
		}
	}
	// 將自定義的上下文對(duì)象傳遞到模板變量中使用
	r.Assigns(g.Map{
		"Context": customCtx,
	})
	// 執(zhí)行下一步請(qǐng)求邏輯
	r.Middleware.Next()
}

這個(gè)中間件初始化了用戶執(zhí)行流程共享的對(duì)象,并且存儲(chǔ)到context.Context變量中的對(duì)象是指針類型*model.Context。

這樣做的好處是:任何一個(gè)地方獲取到這個(gè)指針,不僅可以獲取到里面的數(shù)據(jù),而且能夠直接修改里面的數(shù)據(jù)。

TIPS

如果Session中存在用戶登錄后的存儲(chǔ)信息,那么也會(huì)將需要共享的用戶基本信息寫入到*model.Context中。

四、上下文變量使用

方法定義

方法定義的第一個(gè)輸入?yún)?shù)往往預(yù)留給context.Context類型參數(shù)使用,以便接受上下文變量,特別是service層的方法。

例如:

// 執(zhí)行用戶登錄
func (s *userService) Login(ctx context.Context, loginReq *define.UserServiceLoginReq) error {
    ...
}
// 查詢內(nèi)容列表
func (s *contentService) GetList(ctx context.Context, r *define.ContentServiceGetListReq) (*define.ContentServiceGetListRes, error) {
    ...
}
// 創(chuàng)建回復(fù)內(nèi)容
func (s *replyService) Create(ctx context.Context, r *define.ReplyServiceCreateReq) error {
    ...
}

TIPS

另外一個(gè)好習(xí)慣是:方法的最后一個(gè)返回參數(shù)往往是error類型。如果確定方法內(nèi)部永不會(huì)產(chǎn)生error,那么可以忽略。

Context對(duì)象獲取

通過(guò)service中封裝的以下方法,將context.Context上下文變量傳遞進(jìn)去即可。

context.Context上下文變量在GoFrame框架的HTTP請(qǐng)求中可以通過(guò)r.Context()方法獲取。

GRPC請(qǐng)求中,編譯生成的pb文件中執(zhí)行方法的第一個(gè)參數(shù)即固定是context.Context

service.Context.Get(ctx)

自定義Key-Value

我們可以通過(guò)以下方式設(shè)置/獲取自定義的key-value鍵值對(duì)。

// 設(shè)置自定義鍵值對(duì)
service.Context.Get(ctx).Data[key] = value
...go
// 獲取自定義鍵值對(duì)
service.Context.Get(ctx).Data[key]

五、注意問(wèn)題

  • 上下文變量只傳遞必須的鏈路參數(shù)數(shù)據(jù),不要什么參數(shù)都往里面塞。特別是一些方法參數(shù)、傳參的數(shù)據(jù),千萬(wàn)不能往上下文里面塞,而應(yīng)當(dāng)顯示的傳遞方法參數(shù)。
  • 上下文變量?jī)H用作運(yùn)行時(shí)臨時(shí)使用,不可做持久化存儲(chǔ)長(zhǎng)期使用。

總結(jié)

這篇文章詳細(xì)的為大家介紹了GoFrame上下文對(duì)象Context的知識(shí)點(diǎn):

Context的作用:在業(yè)務(wù)流程中進(jìn)行變量的共享。

Context的結(jié)構(gòu)定義、邏輯封裝、如何在中間件中注入、如何通過(guò)Context設(shè)置值和取值、Context如何自定義key-value、以及在項(xiàng)目開發(fā)中使用的注意問(wèn)題,更多關(guān)于GoFrame共享變量Context的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Go語(yǔ)言中處理JSON數(shù)據(jù)的編碼和解碼的方法

    Go語(yǔ)言中處理JSON數(shù)據(jù)的編碼和解碼的方法

    在Go語(yǔ)言中,處理JSON數(shù)據(jù)的編碼和解碼主要依賴于標(biāo)準(zhǔn)庫(kù)中的encoding/json包,這個(gè)包提供了兩個(gè)核心的函數(shù):Marshal和Unmarshal,本文給大家介紹了Go語(yǔ)言中處理JSON數(shù)據(jù)的編碼和解碼的方法,需要的朋友可以參考下
    2024-04-04
  • 詳解如何在Go中實(shí)現(xiàn)優(yōu)雅停止

    詳解如何在Go中實(shí)現(xiàn)優(yōu)雅停止

    和其他語(yǔ)言相比,Go 中有相同也有不同,相同的是實(shí)現(xiàn)思路上和其他語(yǔ)言沒(méi)啥差異,不同在于 Go 采用的是 goroutine + channel 的并發(fā)模型,與傳統(tǒng)的進(jìn)程線程相比,實(shí)現(xiàn)細(xì)節(jié)上存在差異,本文將從實(shí)際場(chǎng)景和它的一般實(shí)現(xiàn)方式展開,逐步討論這個(gè)話題,需要的朋友可以參考下
    2024-04-04
  • Go語(yǔ)言依賴管理三要素示例解析

    Go語(yǔ)言依賴管理三要素示例解析

    這篇文章主要介紹了Go語(yǔ)言依賴管理三要素及示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • Go語(yǔ)言寫入字符串到文件的方法

    Go語(yǔ)言寫入字符串到文件的方法

    這篇文章主要介紹了Go語(yǔ)言寫入字符串到文件的方法,實(shí)例分析了Go語(yǔ)言操作字符串及文本的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-02-02
  • golang進(jìn)行xml文件解析的操作方法

    golang進(jìn)行xml文件解析的操作方法

    本文介紹了Go語(yǔ)言中解析XML文件的幾種方法:小文件解析、大文件流式解析和復(fù)雜結(jié)構(gòu)解析,對(duì)于小文件,使用標(biāo)準(zhǔn)庫(kù)中的encoding/xml包;對(duì)于大文件,采用流式解析以避免內(nèi)存溢出,對(duì)于復(fù)雜結(jié)構(gòu)的XML文件,推薦使用第三方庫(kù)github.com/beevik/etree
    2024-11-11
  • Go語(yǔ)言實(shí)現(xiàn)LRU算法的核心思想和實(shí)現(xiàn)過(guò)程

    Go語(yǔ)言實(shí)現(xiàn)LRU算法的核心思想和實(shí)現(xiàn)過(guò)程

    這篇文章主要介紹了Go語(yǔ)言實(shí)現(xiàn)LRU算法的核心思想和實(shí)現(xiàn)過(guò)程,LRU算法是一種常用的緩存淘汰策略,它的核心思想是如果一個(gè)數(shù)據(jù)在最近一段時(shí)間內(nèi)沒(méi)有被訪問(wèn)到,那么在將來(lái)它被訪問(wèn)的可能性也很小,因此可以將其淘汰,感興趣想要詳細(xì)了解可以參考下文
    2023-05-05
  • 如何在Golang中運(yùn)行JavaScript

    如何在Golang中運(yùn)行JavaScript

    最近寫一個(gè)程序,接口返回的數(shù)據(jù)是js格式的,需要通過(guò)golang來(lái)解析js,所以下面這篇文章主要給大家介紹了關(guān)于如何在Golang中運(yùn)行JavaScript的相關(guān)資料,需要的朋友可以參考下
    2022-01-01
  • Go導(dǎo)入不同目錄下包報(bào)錯(cuò)的解決方法

    Go導(dǎo)入不同目錄下包報(bào)錯(cuò)的解決方法

    包(package)是多個(gè)Go源碼的集合,是一種高級(jí)的代碼復(fù)用方案,下面這篇文章主要給大家介紹了關(guān)于Go導(dǎo)入不同目錄下包報(bào)錯(cuò)的解決方法,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-06-06
  • Go函數(shù)使用(函數(shù)定義、函數(shù)聲明、函數(shù)調(diào)用等)

    Go函數(shù)使用(函數(shù)定義、函數(shù)聲明、函數(shù)調(diào)用等)

    本文主要介紹了Go函數(shù)使用,包括函數(shù)定義、函數(shù)聲明、函數(shù)調(diào)用、可變參數(shù)函數(shù)、匿名函數(shù)、遞歸函數(shù)、高階函數(shù)等,感興趣的可以了解一下
    2023-11-11
  • Golang實(shí)現(xiàn)IP地址轉(zhuǎn)整數(shù)的方法詳解

    Golang實(shí)現(xiàn)IP地址轉(zhuǎn)整數(shù)的方法詳解

    在 Go 語(yǔ)言中,將 IP 地址轉(zhuǎn)換為整數(shù)涉及到解析 IP 地址并處理其字節(jié)表示,本文給大家介紹了Golang實(shí)現(xiàn)IP地址轉(zhuǎn)整數(shù)的方法,文中有詳細(xì)的代碼示例供大家參考,需要的朋友可以參考下
    2024-02-02

最新評(píng)論

临西县| 治县。| 西城区| 专栏| 金华市| 山西省| 稷山县| 普安县| 新沂市| 汨罗市| 兰州市| 闽清县| 酉阳| 凌海市| 济南市| 罗江县| 巩义市| 绥宁县| 石渠县| 含山县| 朝阳县| 湘潭县| 板桥市| 澄迈县| 莎车县| 南木林县| 二连浩特市| 九龙县| 梁山县| 巴林左旗| 津市市| 温宿县| 铁力市| 丁青县| 右玉县| 苍山县| 元氏县| 大英县| 西昌市| 达日县| 河西区|