概述
golang 似乎为了保证线程安全,context 不允许修改,只能继承,但这样带来的问题就是上文环境无法获取在下文中更新的 context 。
func left(ctx context.Context) { right(ctx) value := GetContextValue(ctx, "key") fmt.Println(value) } func right(ctx context.Context) { ctx := context.WithValue(ctx, "key", "value") } 因为 right 中 context 并没有改变旧的 ctx ,因此 left 中无法获取到 key 的值。
初步想法
我的想法是 ctx 里面塞一个指针,不知道这样是否合理。
// 类似这样,可能不是很准确 func right(ctx context.Context) { sctx := ctx.Value("context").(*SyncContext) sctx.Set(...) } func left(ctx context.Context) { sctx := ctx.Value("context").(*SyncContext) right(ctx) fmt.Println(sctx.Get(...)) } type SyncContext struct { values sync.Map } func NewSyncContext() *SyncContext { ... } func (c *SyncContext) Get(key string) any { ... } func (c *SyncContext) Set(key string, value any) { ... } func main() { ctx := context.WithValue(context.Background(), "context", NewSyncContext()) left(ctx) } 但感觉这种姿势怪怪的。有没有其他的想法?
场景
大概描述一下我的具体场景,http middleware 使用链式调用,第一个中间件是日志中间件,会在所有 next 调用结束后输出日志,请求、响应这些目前都有办法获取了,就是 next 中间件往 req.Context() 写的数据读不到(因为 req.WithContext 也会创建新的 request ,而不是修改 request 的 ctx ,目前看到的代码也没有提供修改 request context 的途径)。
主要是 next 中间件会进行一些身份认证,会把用户信息写进 context ,需要日志最后打出这些用户信息 ( PS:因为这些日志是需要以特定格式输出用于审计的,所以各个中间件自行输出可能会比较难受,主要是想各司其职,不要把心智负担下放到下游中间件)。
