开发者常把 Base64、URL 编码、十六进制统称为“把乱码变成可读文本”的工具,但遇到具体问题时,选错编码往往不是“多几个字符”这么简单:中文参数直接 Base64 后会变成乱码,二进制数据塞进 URL 会导致请求被拦截,十六进制虽然好读但传输量翻倍。

要搞清楚该用哪个,不需要背字典,只需要弄明白一件事:它们各自作用在“字符”上,还是作用在“字节”上。

一、它们解决的不是同一个问题:传输字符集受限 vs URL 语法冲突

Base64 和 Hex 解决的是“传输通道只能接受可打印 ASCII 字符”的问题。比如邮件协议要求内容行只能用 ASCII 字符,上传文件后 API 返回的 JSON 字段里面不能有二进制控制符,这时候需要把字节流转成 Base64 或 Hex。

URL 编码解决的则是“URL 语法保留字符冲突”的问题。URL 里本身含有 ?、&、=、# 等特殊符号,如果查询参数的值里也带这些符号,解析器就会错误截断。URL 编码就是给这些冲突字符加上百分号前缀,让它失去原本的语法含义。

二、URL 编码是百分号转义,作用对象是“字符”,不是“字节流”

URL 编码(percent-encoding)的本质是:把不符合 URL 安全字符集的字符,按照底层字符集(通常是 UTF-8)转成字节序列,再把每个字节用 %XX 表示。

这里的关键点在于:URL 编码的输入输出通常都是“字符串”。它不会改变字符串所代表的语义,只是改变了物理符号。比如把一个中文参数 “中” 丢进去,它会先被转成 UTF-8 字节 E4 B8 AD,再变成 %E4%B8%AD。如果你在 URL 在线编码 里输入一段中文,你会发现输出的结果依然是一串人类可读的“带百分号的文本”,而不是一串完全不认识的密文。这和 Base64 把三个字节变成四个乱码字母的观感完全不同。

三、Base64 作用对象是字节流,但 + / = 会撞 URL 语法

Base64 的输入是“字节流”,输出是 64 个基础可打印字符构成的字符串。它不关心输入到底是中文字符、图片像素,还是加密后的密文,只要是字节就能编码。

但标准 Base64 字母表包含 +、/ 和 =(填充),这三个字符在 URL 里有特殊含义:+ 在 Query 中会被解码成空格,/ 是路径分隔符,= 用于分隔参数名和参数值。所以当你要把一段二进制数据塞进 URL 时,必须换用 Base64url 变体(把 + 换成 -,/ 换成 _,并省略填充)。

四、Hex 是人肉可读的字节表示,代价是长度翻倍

Hex(十六进制)对每个字节直接取两个 4-bit 半字节,映射到 0-9 和 A-F。它的输出永远只包含数字和大写字母,没有任何特殊符号,因此适用于任何通道(包括文件名、日志、纯数字环境)。

代价也很明显:长度翻倍。一段 1KB 的二进制数据变成 Hex 字符串就是 2KB,在带宽紧张的场景下不可接受。所以 Hex 通常只用于“给人看”的场合,比如打印哈希指纹、展示内存地址、颜色码。如果要在这三种方案里做转换测试,可以在 Hex 转 Base64 页面里把同一段字节用两种方式同屏对比,直观看到输出长度的差异。

五、决策流程图:数据放 query / path / header / body / 文件名 分别用什么

既然作用对象不同,选型其实就是一个分类判断:你要处理的东西是“一段 URL 参数”、还是“一堆纯字节”?下面这张表按数据落点排序,直接对照即可:

落点位置数据形态推荐方案原因与注意点
Query / Path 参数纯文本(带中文、空格等)URL 编码浏览器原生支持,语义清晰,不会改变字符实际内容
Query 参数二进制或 JSON 字符串(如 JWT)Base64url + URL 编码先去 Base64 转成安全字符,再过一次 URL 编码处理 = 填充
Header(如 Token)二进制或 JSONBase64urlHeader 规定只能放 ASCII,且不允许 + / 等特殊符号冲突
Body(JSON / XML)二进制或文件Base64(标准表)能保证文本化,且无需考虑 URL 语法冲突
文件名 / 二维码内容任意二进制Hex 或 Base64url文件名一般不许含特殊符号,Hex 绝对安全;二维码存储空间小则用 Base64

在具体验证“先 Base64 再 urlencode”的结果时,可以直接在 URL 在线解码 里看看解码后是不是完整的 Base64 字符串,再拿 Base64 在线编码解码 还原。

六、组合用法:先 gzip 再 base64url 再 urlencode 的三重链路与还原顺序

真实场景中,这三种编码往往不是互斥的,而是串联的。例如“把一份较大的 JSON 塞进 URL 参数”,链路通常是:

1
原始数据
{"name": "张三", "age": 30}
↓ gzip 压缩 ↓
2
压缩后的二进制字节流
0x1F 0x8B 0x08 ...
↓ Base64url 编码 ↓
3
Base64url 文本
H4sIAAAAAAAAA6tWykvM...
↓ URL 编码 ↓
4
最终 URL 参数
data=H4sIAAAAAAAAA6tWykvM...

还原顺序必须相反:先做 URL 解码(拿到 Base64url 字符串)→ 再做 Base64 解码(拿到压缩后的二进制)→ 最后做 gzip 解压(得到原始 JSON)。

这里的坑在于:很多人会把 Base64url 产生的 _ 和 - 直接丢进 URL 参数,却忘记了标准 Base64 里可能带 = 填充符号,而 = 在 URL Query 中会被解析为键值对的分隔符。所以完整链路里,Base64url 之后的 URL 编码是不可省略的。

如果需要临时做一次文件转换测试,可以用 文件转 Base64 在线工具,先确认生成的 Base64 不带换行和多余字符。