修复"不应该在context.WithValue中使用基本类型字符串作为键"golint

sno*_*uis 33 go golint

我正在传递一个uuid使用ContextWithValue处理它的后续函数*http.request.此uuid已在授权标头中传递给REST调用以标识某个人.验证授权令牌并且需要可访问以检查呼叫本身是否已被授权.

我用了:

ctx := context.WithValue(r.Context(), string("principal_id"), *id)
Run Code Online (Sandbox Code Playgroud)

但是高尔特抱怨道:

should not use basic type string as key in context.WithValue
Run Code Online (Sandbox Code Playgroud)

什么是可用于检索此键的最佳选项,该键不是像简单字符串那样的基本类型?

Ain*_*r-G 46

只需使用密钥类型:

type key int

const (
    keyPrincipalID key = iota
    // ...
)
Run Code Online (Sandbox Code Playgroud)

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

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

  • 如果我将上下文传递到另一个模块(其中未导出的“key”不可用)怎么办? (5认同)
  • @endorama您必须提供导出的getter,也许还有setter。`PrincipalIDFromCtx(context.Context) (int64)` 和 `CtxWithPrincipalID(context.Context, int64) (context.Context)`。 (2认同)

F56*_*566 22

使用类型struct{}更好。

type ctxKey struct{} // or exported to use outside the package

ctx = context.WithValue(ctx, ctxKey{}, 123)
fmt.Println(ctx.Value(ctxKey{}).(int) == 123) // true
Run Code Online (Sandbox Code Playgroud)

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

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


RuN*_*ruN 6

我通过执行以下操作实现了上述目标,并且感觉它非常干净

package util

import "context"

type contextKey string

func (c contextKey) String() string {
    return string(c)
}

var (
    // ContextKeyDeleteCaller var
    ContextKeyDeleteCaller = contextKey("deleteCaller")
    // ContextKeyJobID var
    ContextKeyJobID contextKey
)

// GetCallerFromContext gets the caller value from the context.
func GetCallerFromContext(ctx context.Context) (string, bool) {
    caller, ok := ctx.Value(ContextKeyDeleteCaller).(string)
    return caller, ok
}

// GetJobIDFromContext gets the jobID value from the context.
func GetJobIDFromContext(ctx context.Context) (string, bool) {
    jobID, ok := ctx.Value(ContextKeyJobID).(string)
    return jobID, ok
}
Run Code Online (Sandbox Code Playgroud)

..然后设置上下文,

ctx := context.WithValue(context.Background(), util.ContextKeyDeleteCaller, "Kafka Listener")
Run Code Online (Sandbox Code Playgroud)

..从上下文中获取价值,

caller, ok := util.GetCallerFromContext(ctx)
if !ok {
    dc.log.Warn("could not get caller from context")
}
fmt.Println("value is:", caller) // will be 'Kafka Listener'
Run Code Online (Sandbox Code Playgroud)

并且可以通过这样做打印出键的值,

fmt.Println("Key is:", ContextKeyDeleteCaller.String())
Run Code Online (Sandbox Code Playgroud)