传入请求的上下文

时间:2015-02-12 19:39:09

标签: http go request

我不时会遇到" Context" 概念,该概念通常是为所有传入请求创建的。最近,我已阅读使用golang.org/x/net/context包描述的Go blog article。但是,在使用代码并尝试重现文章的逻辑之后,我仍然很难理解如何将它用于每个传入的请求,甚至为什么它对此有用。

如何使用golang.org/x/net/context包为每个传入请求组织我的代码来创建上下文(通常包含哪些内容)?任何人都可以举一个例子来解释什么是如此有用以及为什么如此经常使用?

2 个答案:

答案 0 :(得分:15)

上下文传递最常见的需求之一是将传出请求与传入请求相关联。我已经将它用于各种目的,例如:

  • 我希望我的数据库组件的错误日志包含来自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,....)
}

您当然可以将其限制为需要传递的更有针对性的数据集,而不是整个请求。

上下文包帮助的另一件事(我认为博客可以指出),是超时或截止日期的常见框架。

请注意,上下文包不会为您强制执行超时。由接收上下文对象的组件来监视完成通道并自行取消它们自己的http请求或数据库调用或计算等等。

编辑 - 超时

能够从组件外部管理超时非常有用。如果我有一个数据库模块,我不需要硬编码超时值,只能处理从外部触发的超时。

我这样做的一种方法是在每个传入请求进行多次db / service调用的服务中。如果总时间超过1秒,我想中止所有出站操作并返回部分或错误结果。在顶级使用超时初始化上下文并将其传递给所有依赖项是一种非常简单的方法来管理它。

依赖于听取完成频道并中止其工作并不总是很好,但正如博客所示,它也不是非常痛苦。

答案 1 :(得分:0)

我同意@captncraig的答案。但是我只想轻松地更新与传递上下文有关的代码。

假设您有一条路线build.sbt /foo

在这种情况下,http.Handle("/foo", SimpleContextHandler(passContextHandler))就像一个构造函数,您可以像下面这样初始化它。

SimpleContextHandler

玩得开心,如果您仍然认为它可以改善,请修改我的答案,因为几周前我也开始使用GoLang :)