base64是一种将3字节二进制数据(24位)拆分为4组6位、再映射为可打印ascii字符的编码方法,长度增加约33%,适用于文本环境传输二进制数据。

二进制数据转字符串:别直接用 string() 强转
直接对 []byte 用 string(b) 得到的是 UTF-8 编码的字符串,前提是 b 确实是合法 UTF-8 序列。如果数据来自文件头、网络协议包、加密结果或任意二进制流,大概率含非法字节——这时 string() 不报错但会生成含 (U+FFFD)的损坏字符串,且无法还原原始字节。
- 真正安全的转换,是把二进制数据「编码」为可打印字符串,而非「解码」为文本
- 常见编码方式有:
hex.EncodeToString()(十六进制)、base64.StdEncoding.EncodeToString()(Base64)、encoding/binary配合整数类型(仅适用于结构化数值) - 除非你明确知道该
[]byte是 UTF-8 文本(比如 HTTP 响应体、JSON 字符串),否则不要用string()
Hex 编码:适合调试、日志、校验和显示
十六进制最直观,每个字节转成两个 ASCII 字符(00–ff),无歧义、易读、可逆。Go 标准库提供高效实现:
import "encoding/hex"
<p>data := []byte{0x47, 0x6f, 0x21} // "Go!"
s := hex.EncodeToString(data) // "476f21"
// 还原:b, _ := hex.DecodeString(s)
</p>
-
hex.EncodeToString()输出小写,如需大写用strings.ToUpper()包裹 - 性能敏感场景可用
hex.Encode()直接写入[]byte目标缓冲区,避免额外分配 - 注意:Hex 字符串长度恒为原数据长度的 2 倍,不适合传输或存储压缩
Base64 编码:平衡可读性与空间效率
Base64 把每 3 字节转成 4 个 ASCII 字符(A-Z, a-z, 0-9, +// 或 -/_),体积膨胀约 33%,比 Hex(100% 膨胀)更省空间,适合 API 传输、JWT、嵌入 HTML/CSS 中。
import "encoding/base64"
<p>data := []byte("hello")
s := base64.StdEncoding.EncodeToString(data) // "aGVsbG8="
// URL 安全变种(不用 + /,改用 - _):
// s := base64.URLEncoding.EncodeToString(data)
</p>
- 标准 Base64 末尾可能带
=填充符;URL 安全变种(URLEncoding)省略填充,更适合路径/查询参数 - 解码时若传入非法字符(如空格、换行、非 Base64 字母),
DecodeString()返回错误,必须检查err - 不要在未验证来源的情况下直接
DecodeString()—— 攻击者可构造超长输入触发 OOM
什么时候真该用 string()?
只有两种情况可放心强转:
- 数据来源确定为 UTF-8 文本:比如
io.ReadAll()读取的 JSON 响应、os.ReadFile()读取的配置文件(且已确认文件编码) - 你需要把字节当 Unicode 码点处理(如逐字符遍历),且能容忍非法序列被替换为
其他所有场景——协议字段、哈希值、密钥、图像像素、序列化结构体——都该走编码路径。强行 string() 不仅丢失信息,还会让后续 json.Marshal() 或 http.Header.Set() 出现静默截断或乱码。
真正麻烦的不是选哪种编码,而是混用:比如前端用 Base64 解码,后端却用了 Hex;或者日志里打出了 Hex 字符串,排查时却当成原始字节去比对。统一约定、文档注明、加单元测试校验编解码往返一致性,比选哪个函数更重要。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











