修复”golint中不应使用基本类型字符串作为context.WithValue的键”的问题。

huangapple go评论105阅读模式
英文:

Fix "should not use basic type string as key in context.WithValue" golint

问题

我正在使用ContextWithValue将一个uuid传递给处理*http.request的后续函数。这个uuid是通过授权头部传递给REST调用的,用于标识一个人。授权令牌已经验证,并且需要被访问以检查调用本身是否被授权。

我使用了以下代码:

  1. ctx := context.WithValue(r.Context(), string("principal_id"), *id)

但是golint抱怨:

  1. 不应该将基本类型string作为context.WithValue的键

有什么更好的选项可以用来检索这个键,而不是使用简单的字符串作为基本类型?

英文:

I am passing an uuid in using the Context and WithValue to subsequent functions that handle this *http.request. This uuid is was passed in the authorization header to a REST call to identify a person. The authorization token is verified and needs to accessible to check if the call is itself is authorized.

I used:

  1. ctx := context.WithValue(r.Context(), string("principal_id"), *id)

But golint complains:

  1. should not use basic type string as key in context.WithValue

What is the best option that could be used to retrieve this key that is not a basic type like a simple string?

答案1

得分: 116

只需使用一个键类型:

<!-- language: go -->

  1. type key int
  2. const (
  3. keyPrincipalID key = iota
  4. // ...
  5. )

由于您定义了一个单独的类型,它永远不会发生冲突。即使您有两个包,pkg1.key(0) != pkg2.key(0)

另请参阅:Go博客中关于上下文中键冲突的文章

英文:

Just use a key type:

<!-- language: go -->

  1. type key int
  2. const (
  3. keyPrincipalID key = iota
  4. // ...
  5. )

Since you've defined a separate type, it will never collide. Even if you have two packages, pkg1.key(0) != pkg2.key(0).

See also: Go Blog about key collisions in context.

答案2

得分: 18

使用类型struct{}更好。

  1. type ctxKey struct{} // 或者导出以在包外使用
  2. ctx = context.WithValue(ctx, ctxKey{}, 123)
  3. fmt.Println(ctx.Value(ctxKey{}).(int) == 123) // true

参考:https://golang.org/pkg/context/#WithValue

提供的键必须是可比较的,并且不应该是字符串或任何其他内置类型,以避免在使用上下文的包之间发生冲突。使用WithValue的用户应该为键定义自己的类型。为了在分配给interface{}时避免分配内存,上下文键通常具有具体类型struct{}。或者,导出的上下文键变量的静态类型应该是指针或接口。

英文:

Use type struct{} much better.

  1. type ctxKey struct{} // or exported to use outside the package
  2. ctx = context.WithValue(ctx, ctxKey{}, 123)
  3. fmt.Println(ctx.Value(ctxKey{}).(int) == 123) // true

Reference: https://golang.org/pkg/context/#WithValue

> The provided key must be comparable and should not be of type string or any other built-in type to avoid collisions between packages using context. Users of WithValue should define their own types for keys. To avoid allocating when assigning to an interface{}, context keys often have concrete type struct{}. Alternatively, exported context key variables' static type should be a pointer or interface.

答案3

得分: 5

我通过以下方式实现了上述内容,并且感觉很简洁:

  1. package util
  2. import "context"
  3. type contextKey string
  4. func (c contextKey) String() string {
  5. return string(c)
  6. }
  7. var (
  8. // ContextKeyDeleteCaller 变量
  9. ContextKeyDeleteCaller = contextKey("deleteCaller")
  10. // ContextKeyJobID 变量
  11. ContextKeyJobID contextKey
  12. )
  13. // GetCallerFromContext 从上下文中获取调用者的值。
  14. func GetCallerFromContext(ctx context.Context) (string, bool) {
  15. caller, ok := ctx.Value(ContextKeyDeleteCaller).(string)
  16. return caller, ok
  17. }
  18. // GetJobIDFromContext 从上下文中获取jobID的值。
  19. func GetJobIDFromContext(ctx context.Context) (string, bool) {
  20. jobID, ok := ctx.Value(ContextKeyJobID).(string)
  21. return jobID, ok
  22. }

然后通过以下方式将其设置到上下文中:

  1. ctx := context.WithValue(context.Background(), util.ContextKeyDeleteCaller, "Kafka Listener")

通过以下方式从上下文中获取值:

  1. caller, ok := util.GetCallerFromContext(ctx)
  2. if !ok {
  3. dc.log.Warn("无法从上下文中获取调用者")
  4. }
  5. fmt.Println("值为:", caller) // 将输出 'Kafka Listener'

通过以下方式打印出键的值:

  1. fmt.Println("键为:", ContextKeyDeleteCaller.String())
英文:

I achieve the above by doing the following and feel it's pretty clean

  1. package util
  2. import &quot;context&quot;
  3. type contextKey string
  4. func (c contextKey) String() string {
  5. return string(c)
  6. }
  7. var (
  8. // ContextKeyDeleteCaller var
  9. ContextKeyDeleteCaller = contextKey(&quot;deleteCaller&quot;)
  10. // ContextKeyJobID var
  11. ContextKeyJobID contextKey
  12. )
  13. // GetCallerFromContext gets the caller value from the context.
  14. func GetCallerFromContext(ctx context.Context) (string, bool) {
  15. caller, ok := ctx.Value(ContextKeyDeleteCaller).(string)
  16. return caller, ok
  17. }
  18. // GetJobIDFromContext gets the jobID value from the context.
  19. func GetJobIDFromContext(ctx context.Context) (string, bool) {
  20. jobID, ok := ctx.Value(ContextKeyJobID).(string)
  21. return jobID, ok
  22. }

..and then set on context by,

  1. ctx := context.WithValue(context.Background(), util.ContextKeyDeleteCaller, &quot;Kafka Listener&quot;)

..get value from context by,

  1. caller, ok := util.GetCallerFromContext(ctx)
  2. if !ok {
  3. dc.log.Warn(&quot;could not get caller from context&quot;)
  4. }
  5. fmt.Println(&quot;value is:&quot;, caller) // will be &#39;Kafka Listener&#39;

and can print out value of key by doing,

  1. fmt.Println(&quot;Key is:&quot;, ContextKeyDeleteCaller.String())

答案4

得分: -11

分享对上述问题的简要回答。
GitHub链接
简而言之,context.WithValue()需要将作为interface{}类型。

希望这可以帮到你。
谢谢。

英文:

Sharing a brief answer for the above question.
GitHub Link
In short, context.WithValue() needs interface{} type as keys and values.

I hope this helps.
Thank you.

huangapple
  • 本文由 发表于 2016年11月30日 22:50:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/40891345.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定