http - 即使 gin 的 Context 结构将 Header 作为 Map 也无法获取 Map 的键
问题描述
我无法从 Gin 的 Context.Header(Golang 的 gin-gonic http/rest 框架)字段中获取所有键,即使 Header 被定义为 Map “type Header map[string][]string”(Header 来自net\http\Header.go,request 来自 net\hhtp\request.go,Context 来自 Gin-gonic 的包),奇怪的是即使在编译/构建时,Visual Studio 代码也不让我调用/ 在这个映射类型的 Header 上使用“MapKeys()”方法(鉴于 Golang 是静态类型语言,并且它在编译时已经知道它的数据类型)。
- 我需要将所有的HTTP headers复制到Logger中,这样当我记录任何消息时,我就可以放入相应的请求Headers。
- 而且我还需要将所有 HTTP 标头从 HTTP 传递到 gRPC 调用,以满足端到端调用可追溯性的需要。
func (l *Logger) InfoCtx(ctx *gin.Context, md metadata.MD) *zerolog.Event {
headerName := "X-Request-Id" // Read all the headers from the ENV file
// mapping := make(map[string]string)
// mapping[headerName] = ctx.Request.Header[headerName][0]
event := l.Logger.Info()
// ctx.Request.Header ==> Even though this is a "map" type,
// which is known at the compilation time itself,
// it doesn't let me use any map functions.
if ctx != nil && len(ctx.Request.Header[headerName]) > 0 {
event = event.Str(headerName, ctx.Request.Header[headerName][0])
} else if md != nil {
// some other gRPC metadata context handling (not relevant for this question)
}
return event
}
能否请你帮忙?
解决方案
同时对我有用的另一种方法是,
- 我创建了一个结构,其中包含“HttpHeadersMap map[string][]string”
type CommonContext struct {
HttpHeadersMap map[string][]string
RequestContext context.Context
GrpcMDHeadersMap map[string][]string
}
- 将 Gin 的“ctx.Request.Header”分配给“HttpHeadersMap map[string][]string”
func GetCommonCtx(ctx *gin.Context, md metadata.MD) CommonContext {
var commonContext CommonContext
if ctx != nil {
// event = event.Str(headerName, ctx.Request.Header[headerName][0])
commonContext = CommonContext{ // don't return address, use valye type
HttpHeadersMap: ctx.Request.Header,
RequestContext: ctx.Request.Context(),
}
}
...
}
然后在“gRPC 拦截器(仅显示示例用例)”中,我可以使用“HttpHeadersMap”常规方式作为“headersMapVal.MapKeys()”来迭代 Map 键。
func clientInterceptor(
ctx context.Context,
method string,
req interface{},
reply interface{},
cc *grpc.ClientConn,
invoker grpc.UnaryInvoker,
opts ...grpc.CallOption,
) error {
start := time.Now()
commonCtx := commonContext.GetCommonCtx(nil, metadata.MD{})
if callOpt, ok := opts[0].(CustomDataCallOption); ok {
headersMapVal := reflect.ValueOf(callOpt).FieldByName("HeadersMap")
newMap := make(map[string]string)
// allKeysMap := make(map[string]string)
for _, key := range headersMapVal.MapKeys() {
// fmt.Printf("headersMapVal.MapKeys(), e %v", e)
// c_key := e.Convert(headersMapValueIndirectStr.Type().Key())
keyValue := headersMapVal.MapIndex(key)
...
...
}
推荐阅读
- java - 如何使用反射来判断一个接口是否有默认方法?
- php - 输入网址时图片不显示
- excel - 无法解决错误“运行时错误'1004':对象'_Worksheet'的方法'范围'失败”
- python - 将列标题添加到系列
- api - 定期从 API 获取数据并在全球范围内提供数据的最佳实践(针对每个屏幕)
- swift - Mac OS Big Sur 11.0 上的 MainWindow 为零
- python - 为什么我的 Python 代码在我回答“否”时表现得就像是在回答“是”一样?
- c++ - 如果用户在 C++ 程序中键入的不是浮点数,我该如何更改输入?
- javascript - 为什么数组值仅在第一个函数后更改?
- python - 如何在python中检索列表总和并转换为字典