🐾 大家好,我是猫头虎博主!今天,我要和大家深入探讨Go的一个强大特性——Context
。在Go的服务器中,每个传入请求都在它自己的goroutine中处理。Context
使我们能够在API边界之间,轻松传递请求范围内的值、取消信号和截止日期。如果请求被取消或超时,所有处理该请求的goroutines都应该迅速退出,以便系统能够回收它们正在使用的资源。让我们一起深入了解Context
,并通过一个完整的工作示例来学习如何使用它!🔍
在Go服务器中,每个传入的请求都在自己的goroutine中处理。这些请求处理程序经常启动额外的goroutines来访问后端数据库和RPC服务。处理请求的goroutine集通常需要访问特定于请求的值,例如终端用户的身份、授权令牌和请求的截止时间。当请求被取消或超时时,所有处理该请求的goroutines都应该迅速退出。
Context
类型是context
包的核心。它携带截止日期、取消信号和跨API边界的请求范围值。其方法可被多个goroutines安全使用。Done
方法返回一个通道,当Context
被取消或超时时关闭,Err
方法返回一个错误,指示为什么Context
被取消。
type Context interface {
Done() <-chan struct{}
Err() error
Deadline() (deadline time.Time, ok bool)
Value(key interface{}) interface{}
}
context
包提供了从现有Contexts派生新Contexts的功能。这些值形成一棵树:当一个Context
被取消时,从它派生的所有Contexts
也被取消。
我们的示例是一个HTTP服务器,它处理像/search?q=golang&timeout=1s
这样的URL,通过将查询“golang”转发到谷歌网络搜索API并呈现结果。timeout
参数告诉服务器在该时间段后取消请求。
代码分布在三个包中:
服务器程序处理像/search?q=golang
这样的请求,通过呈现golang
的前几个谷歌搜索结果。它注册handleSearch
来处理/search
端点。处理器创建一个名为ctx
的初始Context
,并安排在处理器返回时取消它。
userip
包提供了从http.Request
中提取用户IP地址并将其与Context
关联的函数。它通过提供HTTP请求到键值对的映射来使处理程序能够将数据与传入请求关联。
google.Search
函数向谷歌网络搜索API发出HTTP请求,并解析JSON编码的结果。它接受一个Context
参数ctx
,并在请求进行中如果ctx.Done
被关闭则立即返回。
许多服务器框架
提供用于携带请求范围值的包和类型。我们可以定义新的Context
接口实现,以便在使用现有框架的代码和期望Context
参数的代码之间架起桥梁。
在谷歌,我们要求Go程序员将Context
参数作为从传入到传出请求之间的调用路径上每个函数的第一个参数。这使得由许多不同团队开发的Go代码能够很好地互操作。它为超时和取消提供了简单的控制,并确保像安全凭证这样的关键值能够正确地通过Go程序传递。