Documentation
¶
Overview ¶
Package convert 提供常用类型转换工具函数。
所有转换函数都支持默认值,转换失败时返回默认值而非 error。
convert.Str2Int64("123", 0) // 123
convert.Str2Int64("abc", 0) // 0 (转换失败返回默认值)
convert.Str2Float64("3.14", 0) // 3.14
convert.Bool2Str(true) // "true"
Index ¶
- func AnyToBool(v any) bool
- func AnyToFloat32(v any) float32
- func AnyToFloat64(v any) float64
- func AnyToInt(v any) int
- func AnyToInt32(v any) int32
- func AnyToInt64(v any) int64
- func AnyToStr(v any) string
- func AnyToStrOr(v any, def string) string
- func AnyToUint64(v any) uint64
- func AppendStrings(a, b []string) []string
- func Bool2Str(b bool) string
- func BoolToBytes(b bool) []byte
- func ByteToBytes(b byte) []byte
- func BytesToFloat32(data []byte) float32
- func BytesToFloat64(data []byte) float64
- func BytesToInt(data []byte) int
- func BytesToInt64(data []byte) int64
- func BytesToString(data []byte) string
- func Convert(data any, target any) error
- func ConvertStruct(src, dst any) error
- func DeepCopy(value any) any
- func DefaultTrustedProxies() []string
- func Float32ToStr(f float32, prec int) string
- func Float64ToBytes(f float64, prec int) []byte
- func Float64ToStr(f float64, prec int) string
- func GetClientIP(r *http.Request) string
- func GetClientIPWithProxies(r *http.Request, trustedProxies []string) string
- func GetClientIPWithProxiesAndXRI(r *http.Request, trustedProxies []string) string
- func GetClientIPWithXRI(r *http.Request) string
- func Int32ToStr(i int32) string
- func Int64ToBytes(i int64) []byte
- func Int64ToStr(i int64) string
- func IntToBytes(i int) []byte
- func IntToStr(i int) string
- func OptBool(v any) *bool
- func OptInt32(v any) *int32
- func OptInt64(v any) *int64
- func OptStr(v any) *string
- func ResolveClientIP(remote, xff string, trustedProxies []string) string
- func ResolveClientIPWithSet(remote, xff string, set *TrustedProxySet) string
- func ResolveClientIPWithSetAndXRI(remote, xff, xri string, set *TrustedProxySet) string
- func ResolveClientIPWithXRI(remote, xff, xri string, trustedProxies []string) string
- func Str2Bool(s string, def bool) bool
- func Str2Float32(s string, def float32) float32
- func Str2Float64(s string, def float64) float64
- func Str2Int(s string, def int) int
- func Str2Int32(s string, def int32) int32
- func Str2Int64(s string, def int64) int64
- func Str2Uint(s string, def uint) uint
- func Str2Uint64(s string, def uint64) uint64
- func StringToBytes(s string) []byte
- func StructToMap(v any) map[string]any
- func Uint64ToStr(u uint64) string
- func UintToStr(u uint) string
- type TrustedProxySet
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AnyToFloat64 ¶
AnyToFloat64 任意类型转 float64,无法转换返回 0。 支持 bool(true=1, false=0)、string/[]byte(按浮点解析)、所有数值类型。
func AnyToInt32 ¶ added in v0.30.0
AnyToInt32 任意类型转 int32,无法转换或超出 int32 表示范围返回 0。
补这一档的原因:有 AnyToInt / AnyToInt64 / AnyToUint64 / AnyToFloat32 / AnyToFloat64,唯独没有 int32——而 JSON 解码出来的数字一律是 float64, 进 int32 契约前必须转。
口径与 AnyToInt64 同族:装不下按「无法转换」处理(返回 0),**不发生 回绕**(回绕会把一个越界值变成符号相反的合法值)。
func AnyToInt64 ¶
AnyToInt64 任意类型转 int64,无法转换返回 0。 支持 bool(true=1, false=0)、string/[]byte(按十进制解析)、所有数值类型。
func AnyToStrOr ¶ added in v0.30.0
AnyToStrOr 返回 v 的字符串形态;v 为 nil 时返回 def。
默认 def 为 "" ⇒ nil 读成空串,而不是 "<nil>"。
与 AnyToStr 的关系:AnyToStr 保持既有语义(不动既有调用点),AnyToStrOr 是 nil 安全的那一档。
func AnyToUint64 ¶
AnyToUint64 任意类型转 uint64,无法转换返回 0。 注意:传入负数会按位重新解释为大正数(uint 语义),调用方应自行确保非负。
func ConvertStruct ¶
ConvertStruct 将 src 结构体的同名字段映射到 dst。 dst 必须是指针。通过反射匹配字段名,相同名称且类型兼容的字段会被复制。
type Src struct { Name string; Age int }
type Dst struct { Name string; Age int }
var d Dst
ConvertStruct(Src{Name: "test", Age: 18}, &d)
func DeepCopy ¶
DeepCopy 对 JSON 动态数据(map[string]any / []any 递归嵌套)进行深拷贝。 仅处理 any 承载的动态容器;强类型容器(如 []map[string]any、 map[string][]string)与其他类型原样返回(浅拷贝),调用方自行注意。
func DefaultTrustedProxies ¶ added in v0.25.2
func DefaultTrustedProxies() []string
DefaultTrustedProxies 返回默认可信代理 CIDR 列表的副本。
返回副本而非包级切片本身:包级切片一旦被调用方改写(append / 排序 / 改元素), 会静默改变本包 GetClientIP 的判定口径。框架适配层(如 Hertz 侧)用本函数 取同一份默认口径,避免各框架各抄一份内网网段清单后各自漂移。
func Float32ToStr ¶
Float32ToStr float32 转字符串,prec 为小数位数(-1 为最短表示)。
func Float64ToBytes ¶
Float64ToBytes float64 转字节切片,prec 为小数位数。
func Float64ToStr ¶
Float64ToStr float64 转字符串,prec 为小数位数(-1 为最短表示)。
func GetClientIP ¶
GetClientIP 从 HTTP 请求中提取真实客户端 IP。 优先级:X-Forwarded-For(仅当请求来自可信代理时) > RemoteAddr。
⚠️ 本函数**不采信 X-Real-IP**——单跳头无法区分「代理写的」与「客户端自带的」, 网关默认透传客户端自带的该头,采信它等于把客户端 IP 的决定权交给客户端 (pkg#106)。确实需要时用 GetClientIPWithXRI。
安全说明:默认只信任内网代理(10/8, 172.16/12, 192.168/16, 127/8)。 如果部署在公网代理后面(如 Cloudflare),需要通过 GetClientIPWithProxies 指定可信代理列表。
func GetClientIPWithProxies ¶
GetClientIPWithProxies 从 HTTP 请求中提取真实客户端 IP,指定可信代理清单。 只有当 RemoteAddr 属于可信代理时,才信任 X-Forwarded-For。 trustedProxies 为 nil 或空时,只使用 RemoteAddr。
⚠️ 本函数**不采信 X-Real-IP**(同 GetClientIP)。
本函数是 net/http 适配层,算法本体在 ResolveClientIP(非 net/http 框架也可复用)。
func GetClientIPWithProxiesAndXRI ¶ added in v0.26.0
GetClientIPWithProxiesAndXRI 指定可信代理清单并额外采信 X-Real-IP。
前置条件同 GetClientIPWithXRI:可信代理必须覆写 X-Real-IP。
func GetClientIPWithXRI ¶ added in v0.26.0
GetClientIPWithXRI 在 GetClientIP 的基础上额外采信 X-Real-IP。
仅在可信代理会**覆写** X-Real-IP 时使用(否则客户端可任意改写自己的客户端 IP, pkg#106)。
func OptBool ¶ added in v0.30.0
OptBool 返回 v 的 bool 形态指针。
v 为 nil、或无法表示为 bool(如 "abc")时返回 nil——**不**返回 &false: 「有一个值为 false 的字段」与「没有这个字段」不是一回事,把前者伪装成 后者就是把不可用值当成了可用值。
func OptInt32 ¶ added in v0.30.0
OptInt32 返回 v 的 int32 形态指针。
v 为 nil、或无法表示为 int32(超范围、不可解析)时返回 nil——超范围的值 装不进 int32 契约,就**没有** int32 值;返回 &0 则是把一个垃圾值伪装成 一个合法值。
func OptStr ¶ added in v0.30.0
OptStr 返回 v 的字符串形态指针;v 为 nil 时返回 nil。
nil 的含义是「**没有这个字段**」——不是「字段的值是空串」。
func ResolveClientIP ¶ added in v0.25.2
ResolveClientIP 是框架无关的客户端 IP 解析纯函数——HTTP 框架只负责把 「对端地址 + X-Forwarded-For 头」取出来,采信判定全部在本函数内。
入参:
- remote:对端地址,形态为 "ip:port" 或裸 IP(IPv4 / IPv6);解析不出端口时按原样当 IP 用。
- xff:X-Forwarded-For 头原文,多段以逗号分隔。
- trustedProxies:可信代理清单(CIDR 或裸 IP);nil 或空时只认 remote(代理头一律忽略)。
采信规则:
- remote 不在可信代理内 ⇒ 返回 remote,**忽略一切代理头** (直连方可以随意伪造 XFF,任何代理头都不可信)。
- remote 在可信代理内 ⇒ 从 XFF **右向左**扫描,跳过可信代理, 返回第一个非可信 IP;XFF 整条链都是可信代理(如内网互调)⇒ 回退到最左端的 原始发起方;XFF 缺失或整条链都没有合法 IP ⇒ 返回 remote。
为什么从右向左:XFF 语义是每个代理把上一跳追加到右端,左侧是客户端可任意伪造的; 从左向右扫描会把攻击者注入的伪造值当成客户端 IP(限流 key / 审计 / 访问控制被绕过)。
候选值合法性:XFF 的每一段都必须能归一为合法 IP 才参与判定——非法段直接跳过, 不进返回值。理由有二:任意字符串进限流/锁定键等于「伪造 IP 永不命中计数 = 绕过」, 且可注入任意内容污染审计日志;带端口的候选归一为裸 IP,避免同一客户端换个端口 就换一个分桶键(pkg#104)。
与 v0.25.2 的差异(BREAKING):
- **不再读取 X-Real-IP**。X-Real-IP 是单跳头,HTTP 头本身无法区分 「代理写的」与「客户端自带的」——大量网关(Envoy / Higress / Traefik)默认 不写该头,但会**原样透传**客户端自带的 X-Real-IP,于是 XFF 那条有右向左 可信链保护的路径与 XRI 这条没有保护的路径信任强度不对等:客户端可以任意 改写自己的客户端 IP(pkg#106)。需要采信 X-Real-IP 的部署请显式调用 ResolveClientIPWithXRI。
- 裸 IP 形态的可信代理条目现在生效(此前被静默忽略,pkg#104)。
- 候选值带端口时归一为裸 IP;非法候选值不再进入返回值。
清单形态的调用每次请求都会重新解析清单(热路径不划算);高 QPS 场景请用 NewTrustedProxySet 构造一次、之后走 ResolveClientIPWithSet(pkg#107)。
清单里的非法条目在本形态下被跳过(历史口径,函数签名无法回报错误);需要 fail-fast 的配置加载路径请用 NewTrustedProxySet。
func ResolveClientIPWithSet ¶ added in v0.26.0
func ResolveClientIPWithSet(remote, xff string, set *TrustedProxySet) string
ResolveClientIPWithSet 用预解析的可信代理集合解析客户端 IP(热路径形态)。
与 ResolveClientIP 的采信规则逐字相同,差别只有一处:清单在构造期解析一次, 请求期不再逐条 ParseCIDR(pkg#107)。set 为 nil 时等价于「不信任任何代理头」。
func ResolveClientIPWithSetAndXRI ¶ added in v0.26.0
func ResolveClientIPWithSetAndXRI(remote, xff, xri string, set *TrustedProxySet) string
ResolveClientIPWithSetAndXRI 是 ResolveClientIPWithSet 与 X-Real-IP 采信的组合。
与 ResolveClientIPWithXRI 同样的前置条件:可信代理必须覆写 X-Real-IP, 否则客户端可任意改写自己的客户端 IP(pkg#106)。
func ResolveClientIPWithXRI ¶ added in v0.26.0
ResolveClientIPWithXRI 在 ResolveClientIP 的基础上**额外**采信 X-Real-IP。
仅在部署形态能保证「可信代理会覆写(而非追加/透传)X-Real-IP」时使用—— 例如 nginx 的 proxy_set_header X-Real-IP $remote_addr(覆写语义)。 若可信代理只是透传客户端自带的 X-Real-IP,本函数等同于把客户端 IP 的决定权 交给客户端:限流/锁定计数桶可被绕过,审计与访问日志的来源 IP 可被改写 (pkg#106)。
func Str2Float32 ¶
Str2Float32 字符串转 float32,失败返回默认值。
func Str2Float64 ¶
Str2Float64 字符串转 float64,失败返回默认值。
func Str2Uint64 ¶
Str2Uint64 字符串转 uint64,失败返回默认值。 负数字符串会解析失败并返回默认值。
func StructToMap ¶
StructToMap 将结构体转为 map[string]any。 通过 json tag 获取 key 名,无 json tag 则用字段名。
Types ¶
type TrustedProxySet ¶ added in v0.26.0
type TrustedProxySet struct {
// contains filtered or unexported fields
}
TrustedProxySet 是预解析的可信代理集合。
存在的理由:按清单逐条 net.ParseCIDR 的写法每请求都要把整份清单重新解析一遍 (清单 N 条 ⇒ 每请求 N 次 ParseCIDR),而解析结果在清单不变时是恒定的 (pkg#107)。构造期解析一次、请求期只做网段包含判定,热路径成本降为一次 预解析 + 若干次位运算。
本类型不可变:构造后只读,可安全跨 goroutine 共享。
func NewTrustedProxySet ¶ added in v0.26.0
func NewTrustedProxySet(proxies []string) (*TrustedProxySet, error)
NewTrustedProxySet 解析可信代理清单为预解析集合(严格模式:非法条目返回错误)。
条目形态:
- CIDR("10.0.0.0/8"):按原样使用;
- 裸 IP("203.0.113.5"):归一为单主机网段(IPv4 /32、IPv6 /128);
- 其它:解析失败即返回错误,**不静默跳过**。
为什么裸 IP 必须归一而不是忽略:清单里写 "203.0.113.5" 的本意是「信任这一台 代理」,而 net.ParseCIDR 对裸 IP 解析失败,旧实现直接 continue —— 于是配置 **不生效且无任何告警**(pkg#104):可信代理悄悄退化成「不信任任何代理头」, 表现为限流 key 变成代理 IP、审计里看不到真实客户端,而查配置看不出任何异常。
为什么非法条目必须报错而不是静默跳过:静默跳过把「配置写错」变成「安全策略 降级」且不可观测;fail-fast 让配置在加载期就红。
空清单合法(等价于「不信任任何代理头」,fail-closed)。
func (*TrustedProxySet) Contains ¶ added in v0.26.0
func (s *TrustedProxySet) Contains(ip net.IP) bool
Contains 判断 IP 是否落在集合内;集合为空或 IP 非法时返回 false。
func (*TrustedProxySet) ContainsString ¶ added in v0.26.0
func (s *TrustedProxySet) ContainsString(ipStr string) bool
ContainsString 判断字符串形态的 IP 是否落在集合内;解析失败返回 false。