修正了“不应该在上下文中使用基本类型字符串作为键

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

我用:

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

但戈林特抱怨道:

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

什么是最好的选择,可以用来检索这个关键,而不是一个基本类型像一个简单的字符串?

34952 次浏览

只需使用键类型:

type key int


const (
keyPrincipalID key = iota
// ...
)

因为您已经定义了一个单独的类型,所以它永远不会发生冲突。

参见: 关于上下文中的键冲突的博客

分享对上述问题的简短回答。 GitHub Link 简而言之,context.WithValue()需要 interface{}型作为 钥匙价值观

希望这个能帮上忙。 谢谢你。

我通过做下面的事情来达到上面的目的,并且感觉它是相当干净的

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
}

然后根据上下文,

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

从上下文中获取价值,

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'

并且可以打印出键的值,

fmt.Println("Key is:", ContextKeyDeleteCaller.String())

更好地使用 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

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

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