55 lines
1.9 KiB
Go
55 lines
1.9 KiB
Go
package utils
|
||
|
||
import (
|
||
"context"
|
||
|
||
"github.com/gogf/gf/v2/frame/g"
|
||
"github.com/gogf/gf/v2/util/gconv"
|
||
)
|
||
|
||
// HeadersOptions 控制请求头透传的差异层。基础两层恒有:
|
||
// 1. 透传 HTTP 请求头(含 Authorization/X-User-Info)
|
||
// 2. X-User-Info 为空且 ctx 携带 user(恢复续跑/异步任务注入的合成用户)时补 X-User-Info
|
||
type HeadersOptions struct {
|
||
ResolveToken bool // X-User-Info 仍为空时,解析调用方 token 得到用户注入(直连场景)
|
||
TokenFromQuery bool // Authorization 为空时从 URL query ?token= 补 Bearer(WS 握手)
|
||
}
|
||
|
||
// HeadersFromCtx 统一构造调用方请求头透传 map。全项目唯一的拼头入口
|
||
//
|
||
// 放这里而非 common/http:本函数只依赖 GetUserInfo(同包),与 gclient/gsvc/consul/jaeger 客户端
|
||
// 基础设施零耦合;common/http 空导入 common/consul、common/jaeger(init 里 g.Cfg().MustGet 无默认值,
|
||
// 无配置文件环境会 panic),common/oss 等消费方特意避开它,放 utils 依赖链干净。
|
||
func HeadersFromCtx(ctx context.Context, opts ...HeadersOptions) map[string]string {
|
||
op := HeadersOptions{}
|
||
if len(opts) > 0 {
|
||
op = opts[0]
|
||
}
|
||
headers := make(map[string]string)
|
||
if r := g.RequestFromCtx(ctx); r != nil {
|
||
for k, v := range r.Request.Header {
|
||
if len(v) > 0 {
|
||
headers[k] = v[0]
|
||
}
|
||
}
|
||
}
|
||
if headers["X-User-Info"] == "" {
|
||
if u := ctx.Value("user"); !g.IsNil(u) {
|
||
headers["X-User-Info"] = gconv.String(u)
|
||
}
|
||
}
|
||
if op.TokenFromQuery && headers["Authorization"] == "" {
|
||
if r := g.RequestFromCtx(ctx); r != nil {
|
||
if t := r.Request.URL.Query().Get("token"); t != "" {
|
||
headers["Authorization"] = "Bearer " + t
|
||
}
|
||
}
|
||
}
|
||
if op.ResolveToken && headers["X-User-Info"] == "" {
|
||
if user, err := GetUserInfo(ctx); err == nil && user != nil {
|
||
headers["X-User-Info"] = gconv.String(user)
|
||
}
|
||
}
|
||
return headers
|
||
}
|