Base64 做了什么
它把每 3 字节二进制变成 4 个可打印字符,目的只是让数据能安全地放进只认文本的协议(邮件、JSON、URL)。它不提供任何保密性。
该用的时候
- 在 JSON 里传图片或文件内容(data URL、附件);
- 把证书、令牌塞进文本配置;
- 需要肉眼可逆地表示二进制。
别这样用
- 当加密用:谁都能解码,等于明文;敏感内容请用 AES 等;
- 忽略体积:体积增大约 33%,大文件别硬塞进 JSON;
- 当作压缩:Base64 反而变大,压缩请用 gzip。
动手试试
编码与解码:Base64 编解码。
实战案例:三个用错 Base64 的场景
- 把 Base64 当加密:接口返回
eyJpZCI6MX0=就以为“破解不了”,实际一行解码即可还原。要保密用 AES,要防篡改用签名。 - 大图内联拖慢首屏:把 500KB 的图转成 data URI 塞进 CSS,体积增大约 33%,还无法单独缓存与并行加载。几 KB 的小图标可内联,大图仍应走独立文件。
- URL 里直接塞标准 Base64:
+、/、=会被转义或截断,导致参数错位。放进 URL 请改用 URL 安全变体(+换成-、/换成_并去掉=)。
常见问题(FAQ)
Base64 能压缩吗?不能,反而让体积增大约 33%。为什么编码后长度是 4 的倍数?因为每 3 字节映射为 4 个字符,不足时用 = 补齐。中文直接 btoa 为什么报错?btoa 只接受 Latin-1,中文须先用 TextEncoder 转成字节。适合在数据库里长期存大字段吗?不适合,既占空间又难查询,应改用二进制字段或对象存储。
体积与性能实测
Base64 的代价能量化,决策就不靠感觉:
- 体积:编码后原始数据增长约
33%(4/3),再叠加换行与填充会再多几个百分点; - 内存:字符串形式的 Base64 在 JS 里按 UTF-16 存放,实际内存占用可能是原始字节的两倍以上;
- 压缩:JSON 里的大段 Base64 用 gzip 传输收益很大(Base64 字符集小、重复度高),但压缩只能弥补传输,弥补不了内存;
- 解析:浏览器解码 data URI 需要先解析字符串再转字节,大对象会阻塞主线程,数 MB 以上建议改用
Blob或直接走后端接口。
用流式思路处理大文件
Node 里不要用 readFileSync 读整文件再转 Base64,改用流式编码:逐块 chunk.toString('base64') 并注意每块长度必须是 3 的倍数,否则块边界会产生错误的填充。浏览器里可用 FileReader.readAsDataURL 或 Blob 配合 URL.createObjectURL,避免把大对象整体放进内存。
判断该不该用的三个问题
- 这段数据**必须**经过只能传文本的通道吗?不是就别编码;
- 它是不是小于几 KB?更大就用二进制或独立文件;
- 它是**长期存储**还是**一次性传输**?长期存储应放对象存储,字段里只存引用。
跨端兼容性注意
- 换行与空白:MIME 风格的 Base64 会每 76 字符换行,解码前应先剔除空白与换行,否则解析失败;
- URL 安全变体:
-与_版本与标准版本不通用,混用会解码出错,转换时记得做替换; - 填充可选:部分实现允许省略
=,但严格解码器会拒绝,跨系统传输时建议保留填充; - 大小写敏感:Base64 区分大小写,任何“顺手转小写”的处理都会破坏数据。
安全边界提示
Base64 常被误当作“轻度混淆”。请记住它不提供任何保密性:任何看到密文的人都能立即还原。若确实需要防止“被顺手看到”,至少应使用带密钥的加密或签名,并明确区分“编码”与“加密”在合规与审计中的不同含义。
与压缩的配合顺序
若既要压缩又要编码,顺序是“先压缩再 Base64”。反过来先编码会破坏原始数据的重复性,压缩率大幅下降,体积甚至比不压缩更大。同理,解码时应 Base64 解码后再解压。
与日志的关系
把 Base64 结果直接写进日志会显著增加日志体积并降低可读性,排查时也难以对照原文。若必须记录,建议同时保存原文摘要与长度,或仅在调试级别输出,避免长期占用存储与索引资源。