Is this a correct way of using context in Go 1.7 ?

polaris · · 617 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>I updated my tiny router (violetear.org) to use now the standard context library. (<a href="https://github.com/nbari/violetear/blob/develop/violetear.go#L150-L159" rel="nofollow">https://github.com/nbari/violetear/blob/develop/violetear.go#L150-L159</a>)</p> <p>Basically per request I pass a context with any matching &#34;named parameters&#34; for example if there is a defined route with duplicate parameters: </p> <pre><code>router.HandleFunc(&#34;/test/:uuid/:uuid&#34;, handler) </code></pre> <p>I create a slice so that I could later extract the fields using something like :</p> <pre><code>params := r.Context().Value(&#34;:uuid&#34;).([]interface{}) </code></pre> <p>And use params[0] o params[1]</p> <p>If there are no duplicates on the route, something like:</p> <pre><code>router.HandleFunc(&#34;/test/:foo/:bar&#34;, handler) </code></pre> <p>I just use: </p> <pre><code>foo := r.Context().Value(&#34;:foo&#34;) bar := r.Context().Value(&#34;:bar&#34;) </code></pre> <p>Seems to be working but would like to know if is a valid/correct way of using the context or if something could be improved.</p> <p>Thanks in advance.</p> <hr/>**评论:**<br/><br/>tv64738: <pre><p>I don&#39;t see why this should go in a context. The handler has to know about the url path and the data you&#39;re extracting from it, to understand what your &#34;uuid&#34; key even means. This is not generic request-scoped data, such as authentication/authorization.</p> <p>Storing string-keyed values in context is a recipe for pain.</p></pre>xargon7: <pre><p>Take a quick look at how <a href="https://github.com/golang/go/blob/master/src/context/context.go#L468" rel="nofollow">(context.Context).Value() works</a>. It&#39;s not using a hash map, it uses an iterative key-value comparison.</p> <p>That means that it&#39;s slow for more than a small number of keys. Instead, you should store request-scoped data in another structure within the context.</p> <p>For example:</p> <pre><code>params := r.Context().Value(violetear.ParamsKey) uuid, foo, bar := params[&#34;uuid&#34;], params[&#34;foo&#34;], params[&#34;bar&#34;] </code></pre> <p>What is the ParamsKey? Another thing about storing data in a context is that you want to be really sure that your key never collides with anyone else&#39;s key. If you use a string, it might collide, even if you think it&#39;s unlikely (&#34;violetear<strong>private</strong>ParamsKey__super_secret&#34;).</p> <p>Instead, use a private type, like this:</p> <pre><code>type key int const ParamsKey key = 0 </code></pre> <p>(see <a href="https://blog.golang.org/context" rel="nofollow">https://blog.golang.org/context</a> for more info)</p> <p>To initialize the parameters in the router&#39;s request handler, you&#39;d do something like this:</p> <pre><code>params := map[string]string{} ...fill in params... r = r.WithContext(context.WithValue(r.Context(), ParamsKey, params)) </code></pre></pre>nbari: <pre><p>Hi, many thanks for the explanation and examples.</p></pre>: <pre><p>[deleted]</p></pre>nbari: <pre><p>Hi, thanks for the feedback, seems interesting the approach of having a constant that way I could avoid the use of type casting but can&#39;t fully understand it, could you please elaborate more, for example how to populate the map and reset the constant for all new request, and also how to retrieve the map in the handler side. </p></pre>bonekeeper: <pre><p>The manual pages for Context explicitly talk about not using the context to store data like that.</p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

617 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传