英文:
Fix "should not use basic type string as key in context.WithValue" golint
问题
我正在使用Context
和WithValue
将一个uuid传递给处理*http.request
的后续函数。这个uuid是通过授权头部传递给REST调用的,用于标识一个人。授权令牌已经验证,并且需要被访问以检查调用本身是否被授权。
我使用了以下代码:
ctx := context.WithValue(r.Context(), string("principal_id"), *id)
但是golint抱怨:
不应该将基本类型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:
ctx := context.WithValue(r.Context(), string("principal_id"), *id)
But golint complains:
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 -->
type key int
const (
keyPrincipalID key = iota
// ...
)
由于您定义了一个单独的类型,它永远不会发生冲突。即使您有两个包,pkg1.key(0) != pkg2.key(0)
。
另请参阅:Go博客中关于上下文中键冲突的文章。
英文:
Just use a key type:
<!-- language: go -->
type key int
const (
keyPrincipalID key = iota
// ...
)
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{}
更好。
type ctxKey struct{} // 或者导出以在包外使用
ctx = context.WithValue(ctx, ctxKey{}, 123)
fmt.Println(ctx.Value(ctxKey{}).(int) == 123) // true
参考:https://golang.org/pkg/context/#WithValue
提供的键必须是可比较的,并且不应该是字符串或任何其他内置类型,以避免在使用上下文的包之间发生冲突。使用WithValue的用户应该为键定义自己的类型。为了在分配给interface{}时避免分配内存,上下文键通常具有具体类型struct{}。或者,导出的上下文键变量的静态类型应该是指针或接口。
英文:
Use type struct{}
much better.
type ctxKey struct{} // or exported to use outside the package
ctx = context.WithValue(ctx, ctxKey{}, 123)
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
我通过以下方式实现了上述内容,并且感觉很简洁:
package util
import "context"
type contextKey string
func (c contextKey) String() string {
return string(c)
}
var (
// ContextKeyDeleteCaller 变量
ContextKeyDeleteCaller = contextKey("deleteCaller")
// ContextKeyJobID 变量
ContextKeyJobID contextKey
)
// GetCallerFromContext 从上下文中获取调用者的值。
func GetCallerFromContext(ctx context.Context) (string, bool) {
caller, ok := ctx.Value(ContextKeyDeleteCaller).(string)
return caller, ok
}
// GetJobIDFromContext 从上下文中获取jobID的值。
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("无法从上下文中获取调用者")
}
fmt.Println("值为:", caller) // 将输出 'Kafka Listener'
通过以下方式打印出键的值:
fmt.Println("键为:", ContextKeyDeleteCaller.String())
英文:
I achieve the above by doing the following and feel it's pretty clean
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
}
..and then set on context by,
ctx := context.WithValue(context.Background(), util.ContextKeyDeleteCaller, "Kafka Listener")
..get value from context by,
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'
and can print out value of key by doing,
fmt.Println("Key is:", 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论