2 回答
TA贡献1966条经验 获得超4个赞
上下文传递最常见的需求之一是将传出请求与传入请求相关联。我已将其用于多种目的,例如:
我希望我的数据库组件的错误日志包含来自它的 http 请求的完整 url。
传入的 http 请求包含一组标头,我需要保留这些标头并将其传递给我下游调用的其他 http 服务(可能是出于跟踪原因)。
我想检查其他组件中传入的 http 请求,以进行访问控制或用户身份验证或其他任何操作。这可能在 http 处理程序层,或我的应用程序的其他部分。
许多语言和平台都有方便/神奇的方式来获取当前的 Http 请求。C# 具有HttpRequest.Current
全局可用(通过线程本地存储)的任何想要了解当前 http 请求上下文的人。您可以在其上设置任意数据以传达各种上下文数据。其他平台也有类似的设施。
由于 go 没有用于 goroutine 本地存储的设施,因此无法在当前 http 请求的上下文中存储全局变量。相反,在系统边界(传入请求)初始化上下文是惯用的,并将其作为参数传递给需要访问该信息的任何下游组件。
一种非常简单的方法是使用当前的 http 请求创建一个上下文对象并传递它:
func someHandler(w http.ResponseWriter, r * http.Request){ ctx := context.WithValue(context.Background(),"request",r) myDatabase.doSomething(ctx,....)}
您当然可以将其限制为您需要传递的更有针对性的数据集,而不是整个请求。
上下文包的另一件事(我认为该博客在指出方面做得很好)是超时或截止日期的通用框架。
请注意,上下文包不会为您强制超时。由接收上下文对象的组件来观察 Done 通道并自行取消他们自己的 http 请求或数据库调用或计算或其他任何东西。
编辑 - 超时
能够从组件外部管理超时非常有用。如果我有一个数据库模块,我不需要硬编码超时值,只需能够处理从外部触发的超时。
我这样做的一种方法是在每个传入请求进行多个数据库/服务调用的服务中。如果总时间超过 1 秒,我想中止所有出站操作并返回部分或错误结果。在顶层使用超时初始化上下文并将其传递给所有依赖项是一种非常简单的管理方法。
依赖项收听 Done 频道并中止它的工作并不总是很漂亮,但正如博客所示,它也不是非常痛苦。
TA贡献2039条经验 获得超7个赞
我同意这里的@captncraig 回答。但我只是想轻松更新与传递上下文相关的代码。
假设你有一条路线 /foo http.Handle("/foo", SimpleContextHandler(passContextHandler))
在这种情况下SimpleContextHandler就像一个构造函数,你可以像下面一样启动它。
type SimpleContextHandler func(w http.ResponseWriter, r *http.Request)
func (fn SimpleContextHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ctx := context.WithValue(context.Background(), "Foo", "bar")
fn(w, r.WithContext(ctx))
}
func passContextHandler(w http.ResponseWriter, r *http.Request) {
bar := r.Context().Value("Foo").(string)
w.Write([]byte(bar))
}
玩得开心,如果您仍然觉得可以改进,请编辑我的答案,因为几周前我也开始使用 GoLang :)
- 2 回答
- 0 关注
- 154 浏览
添加回答
举报