Files
rootandClaude Opus 4.7 79ac89b458 Initial commit
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-11-07 10:47:18 +08:00

195 lines
5.1 KiB
Go

package useragent
import (
"context"
"net/url"
"strings"
"videoweb/pub/common/enum/consts"
"videoweb/pub/common/log"
"github.com/gin-gonic/gin"
)
type UA struct {
UserAgent string
DevID string
DevType string
SysType string
Ver string
BuildID string
SystemName string
SystemVersion string
DeviceBrand string
DeviceModel string
SessionID string
SDKCommon *SDKCommonFields // SDK 公共参数独立保存,不能与原业务 UA 字段混用。
RequestPath string // 仅用于定位埋点参数缺失的业务接口。
}
func IsH5(sysType string) bool {
if sysType == consts.H5IOS || sysType == consts.H5Android || sysType == consts.H5PC || sysType == consts.H5 || sysType == consts.Light {
return true
}
return false
}
func (s UA) IsH5() bool {
return IsH5(s.SysType)
}
// FromContext 读取当前请求已经解析好的 UA。下单要在请求结束前把这份值存进订单。
func FromContext(ctx context.Context) UA {
if ctx == nil {
return UA{}
}
if c, ok := ctx.(*gin.Context); ok {
if value, exists := c.Get(consts.CtxUA); exists {
if ua, ok := value.(UA); ok {
return ua
}
}
}
if value := ctx.Value(consts.CtxUA); value != nil {
if ua, ok := value.(UA); ok {
return ua
}
}
return UA{}
}
func UserAgent(c *gin.Context) {
var uastr string
ua := UA{RequestPath: c.FullPath()}
var sdkErr error
ua.SDKCommon, sdkErr = ParseSDKCommonHeader(c.GetHeader(SDKCommonHeader))
if sdkErr != nil {
log.Error("【SDK公共参数解析失败】UserAgent", log.Any("接口", ua.RequestPath), log.E(sdkErr))
}
ua.SessionID = c.GetHeader("sid")
userAgent := c.GetHeader("X-User-Agent") // 兼容 H5 UserAgent
if userAgent == "" {
userAgent = c.Request.UserAgent()
}
c.Set(consts.CtxUAH5, c.Request.UserAgent())
if userAgent != "" {
decodeUa, err := url.QueryUnescape(userAgent)
if err != nil {
log.Warn("URLDecode user-agent error", log.Any("ua", userAgent))
uastr = userAgent
} else {
uastr = decodeUa
}
uas := strings.Split(uastr, ";")
for _, v := range uas {
segment := strings.TrimSpace(v)
if segment == "" {
continue
}
vss := strings.SplitN(segment, "=", 2)
if len(vss) < 2 {
continue
}
key := strings.TrimSpace(vss[0])
value := strings.TrimSpace(vss[1])
lowerKey := strings.ToLower(key)
switch lowerKey {
case "devid":
ua.DevID = value
c.Set(consts.CtxDevId, ua.DevID)
case "devtype":
ua.DevType = value
c.Set(consts.CtxDevType, ua.DevType)
case "systype":
inputSysType := strings.ToLower(strings.TrimSpace(value))
switch {
case strings.Contains(inputSysType, "h5_android"):
ua.SysType = consts.H5Android
case strings.Contains(inputSysType, "h5_ios"):
ua.SysType = consts.H5IOS
case strings.Contains(inputSysType, "h5_pc"):
ua.SysType = consts.H5PC
case strings.Contains(inputSysType, "android"):
ua.SysType = consts.Android
case strings.Contains(inputSysType, "ios"):
ua.SysType = consts.IOS
case strings.Contains(inputSysType, "h5"):
ua.SysType = consts.H5
case strings.Contains(inputSysType, "pc"):
ua.SysType = consts.PC
case strings.Contains(inputSysType, "light"):
ua.SysType = consts.Light
}
c.Set(consts.CtxSysType, ua.SysType)
case "ver":
ua.Ver = value
c.Set(consts.CtxVersion, ua.Ver)
case "buildid":
ua.BuildID = value
c.Set(consts.CtxBuildId, ua.BuildID)
case "system_name", "system-name", "systemname":
if ua.SystemName == "" {
ua.SystemName = value
}
case "system_version", "system-version", "systemversion":
if ua.SystemVersion == "" {
ua.SystemVersion = value
}
case "device_brand", "device-brand", "devicebrand":
if ua.DeviceBrand == "" {
ua.DeviceBrand = value
}
case "device_model", "device-model", "devicemodel":
if ua.DeviceModel == "" {
ua.DeviceModel = value
}
case "sid":
if ua.SessionID == "" {
ua.SessionID = value
}
default:
log.Warn("user-agent unknown", log.Any("ua", userAgent), log.Any("segment", segment))
}
}
} else {
log.Warn("user-agent empty")
}
ua.UserAgent = uastr
if ua.DeviceBrand == "" {
brand := strings.TrimSpace(c.GetHeader("device_brand"))
if brand == "" {
brand = strings.TrimSpace(c.GetHeader("device-brand"))
}
ua.DeviceBrand = brand
}
if ua.DeviceModel == "" {
model := strings.TrimSpace(c.GetHeader("device_model"))
if model == "" {
model = strings.TrimSpace(c.GetHeader("device-model"))
}
ua.DeviceModel = model
}
if ua.SystemName == "" {
name := strings.TrimSpace(c.GetHeader("system_name"))
if name == "" {
name = strings.TrimSpace(c.GetHeader("system-name"))
}
ua.SystemName = name
}
if ua.SystemVersion == "" {
version := strings.TrimSpace(c.GetHeader("system_version"))
if version == "" {
version = strings.TrimSpace(c.GetHeader("system-version"))
}
ua.SystemVersion = version
}
if ua.SystemName == "" {
ua.SystemName = ua.SysType
}
if ua.SystemVersion == "" {
ua.SystemVersion = ua.Ver
}
c.Set(consts.CtxSystemName, ua.SystemName)
c.Set(consts.CtxSystemVersion, ua.SystemVersion)
c.Set(consts.CtxUA, ua)
}