Go_context包

是什么?为什么?

context时goroutine之间传递上下文消息,包括信号取消,储存数据。

为什么?

Go通常写后端服务,启动一个HTTP请求会启动多个goroutine,可以共享token数据。

或者处理时间长,通过停止信号关联goroutine退出。

怎么用?共享数据,定时取消。

使用context共享数据

Go 复制代码
// 使用context在不同goroutine中共享数据
func main() {
	ctx := context.Background() //初始化一个context
	process(ctx)
	ctx = context.WithValue(ctx, "traceId", "5213") //给context添加数据
	process(ctx)
}

func process(ctx context.Context) { // 在函数中传递context
	traceId, ok := ctx.Value("traceId").(string) // 获取context值
	if ok {
		fmt.Printf("process over. trace_id=%s\n", traceId)
	} else {
		fmt.Printf("process over. no trace_id\n")
	}
}
Go 复制代码
// 现实场景中可能是从一个 HTTP 请求中获取到的 Request-ID。
// requestIDKey 用作在 context 中设置和获取请求 ID 的键
// 定义一个特殊的类型可以避免在不同的包之间使用 context 时发生键的冲突
type contextKey string

const requestIDKey contextKey = "requestID"

// WithRequestID 是一个中间件,它将请求ID从请求头中提取出来,
// 然后将这个ID添加到当前请求的context中。
func WithRequestID(next http.Handler) http.Handler {
	return http.HandlerFunc(
		func(rw http.ResponseWriter, req *http.Request) {
			// 从请求头中获取请求ID
			reqID := req.Header.Get("X-Request-ID")

			// 使用context.WithValue创建一个新的context,
			// 其中包含了从请求头中提取出来的请求ID。
			// requestIDKey是用作在context中设置和获取请求ID的键。
			ctx := context.WithValue(req.Context(), requestIDKey, reqID)

			// 使用req.WithContext创建一个新的请求,
			// 其context已经包含了请求ID。
			req = req.WithContext(ctx)

			// 调用下一个处理器(或中间件),
			// 并将更新了context的请求传递给它。
			next.ServeHTTP(rw, req)
		})
}

// 从Context中获取数据
func GetRequestID(ctx context.Context) string {
	return ctx.Value(requestIDKey).(string) // 从Context中获取Request-ID
}

// 中间件处理函数
func Handle(rw http.ResponseWriter, req *http.Request) {
	reqID := GetRequestID(req.Context()) //从请求中的Context中获取Request-ID
	rw.Write([]byte(reqID))
	fmt.Println(reqID)
}
func main() {
	//type HandlerFunc func(ResponseWriter, *Request) 把func(ResponseWriter, *Request)函数转换成HandlerFunc类型实现了Handler接口
	handler := WithRequestID(http.HandlerFunc(Handle))
	err := http.ListenAndServe("127.0.0.1:8000", handler)
	if err != nil {
		fmt.Println("服务器启动失败")
	}
}

使用context定时取消

Go 复制代码
// 使用context定时取消 
func main() {
	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
	defer cancel()
	ids := fetchWebData(ctx)
	fmt.Println(ids)

}

// 获取web数据
func fetchWebData(ctx context.Context) (res string) {
	select {
	case <-time.After(3 * time.Second):
		return "张三"
	case <-ctx.Done():
		return "超时"

	}
}
相关推荐
2501_931803759 小时前
Go:一门为解决C语言痛点而生的现代语言
c语言·开发语言·golang
geovindu10 小时前
go: Interpreter Pattern
开发语言·设计模式·golang·解释器模式
平凡但不平庸的码农14 小时前
Go Channel详解
开发语言·后端·golang
子安柠14 小时前
深入理解 Go 语言文件操作:从基础到最佳实践
开发语言·后端·golang
Achou.Wang14 小时前
go语言中使用等待组(waitgroups)和内存屏障(barriers)进行同步
开发语言·后端·golang
金玉满堂@bj17 小时前
Go 语言能做什么?
开发语言·后端·golang
geovindu17 小时前
go:Condition Variable Pattern
开发语言·后端·设计模式·golang·条件变量模式
金玉满堂@bj17 小时前
Gin 框架零基础全套入门教程(Go 企业级 Web 开发)
前端·golang·gin
jieyucx1 天前
Go语言深度解剖:Map扩容机制全解析(增量扩容+等量扩容+渐进式迁移)
开发语言·后端·golang·map·扩容策略
王码码20351 天前
Go语言的内存管理:原理与实战
后端·golang·go·接口