1. 概述
本文深入探讨 Java 中实现 Base64 编码与解码的多种方式。主要内容包括:
✅ Java 8 原生提供的 java.util.Base64
API
✅ Apache Commons Codec 库的使用
✅ 常见踩坑点与最佳实践
Base64 并非加密手段,而是一种二进制数据转文本字符串的编码方式,广泛用于 HTTP 接口传输、JWT Token、图片内联等场景。本文面向有一定经验的开发者,基础概念不赘述。
2. Java 8 原生 Base64 支持
Java 8 终于在标准库中引入了 java.util.Base64
工具类,无需再依赖第三方库,简单粗暴又安全。
该类提供了三种编码器:
- Basic:基础编码,无换行
- URL and Filename Safe:适用于 URL 和文件名
- MIME:符合 MIME 标准,每行最多 76 字符
2.1 基础 Base64 编码/解码
基础编码使用 A-Za-z0-9+/
字符集,输出无换行。
String originalInput = "test input";
String encodedString = Base64.getEncoder().encodeToString(originalInput.getBytes());
⚠️ 注意:getBytes()
默认使用平台编码(如 Windows 是 GBK),建议显式指定字符集避免乱码。
解码也很直观:
byte[] decodedBytes = Base64.getDecoder().decode(encodedString);
String decodedString = new String(decodedBytes, StandardCharsets.UTF_8);
✅ 推荐始终指定 UTF-8
字符集,避免跨平台问题。
2.2 无填充(Without Padding)编码
Base64 要求输出长度为 4 的倍数,不足时用 =
填充。但在某些场景(如生成 token)中,=
可能引发 URL 转义问题。
此时可使用无填充编码:
String encodedString =
Base64.getEncoder().withoutPadding().encodeToString(originalInput.getBytes(StandardCharsets.UTF_8));
⚠️ 无填充编码后,必须使用对应的无填充解码器,否则会抛 IllegalArgumentException
。
// ❌ 错误:使用普通解码器
Base64.getDecoder().decode(encodedString); // 可能报错
// ✅ 正确:使用无填充解码器
Base64.getDecoder().decode(encodedString); // 实际上 Java 8 的 getDecoder() 能自动处理无填充
📌 小知识:Java 8 的
getDecoder()
其实能兼容无填充字符串,但为了语义清晰,建议编码时用withoutPadding()
,解码时无需特别处理。
2.3 URL 安全 Base64 编码
当 Base64 字符串用于 URL 参数或文件名时,+
和 /
可能引起问题(如被误认为路径分隔符)。此时应使用 URL 安全编码,它将 +
替换为 -
,/
替换为 _
。
String originalUrl = "https://www.example.com/?q=java+base64";
String encodedUrl = Base64.getUrlEncoder().encodeToString(originalUrl.getBytes(StandardCharsets.UTF_8));
解码使用对应的 URL 解码器:
byte[] decodedBytes = Base64.getUrlDecoder().decode(encodedUrl);
String decodedUrl = new String(decodedBytes, StandardCharsets.UTF_8);
✅ 这种编码方式在 JWT、OAuth Token 中非常常见,属于“标准操作”。
2.4 MIME Base64 编码
MIME 编码用于邮件等场景,每行不超过 76 个字符,并以 \r\n
换行。
先准备一段长文本:
private static StringBuilder getMimeBuffer() {
StringBuilder buffer = new StringBuilder();
for (int count = 0; count < 10; ++count) {
buffer.append(java.util.UUID.randomUUID().toString());
}
return buffer;
}
进行 MIME 编码:
StringBuilder buffer = getMimeBuffer();
String encodedMime = Base64.getMimeEncoder().encodeToString(buffer.toString().getBytes(StandardCharsets.UTF_8));
输出示例(每行 76 字符):
OWQzZDQ1YjMtZjIzYi00Y2I0LWJhZjktY2U1ZjU3ZjM5YjQ1CjE0NzUyZmU5LTg4NDMtNGUw
YS1hZjY2LWU1Y2MwNzQ5M2EwNQphYjMwZjQwZi03ZjU5LTRlZjktYjZjMi1jZjFhZDQxZDc1
...
解码:
byte[] decodedBytes = Base64.getMimeDecoder().decode(encodedMime);
String decodedMime = new String(decodedBytes, StandardCharsets.UTF_8);
⚠️ MIME 解码器能自动忽略换行符,无需预处理。
3. 使用 Apache Commons Codec
虽然 Java 8 提供了原生支持,但 Commons Codec 依然广泛用于老项目或需要更灵活控制的场景。
3.1 添加依赖
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.16.0</version>
</dependency>
3.2 创建 Base64 实例
Commons Codec 提供多个构造函数:
new Base64()
:基础编码new Base64(true)
:URL 安全模式new Base64(76, "\r\n".getBytes())
:自定义行长度和分隔符
示例:
String originalInput = "test input";
Base64 base64 = new Base64();
byte[] encodedBytes = base64.encode(originalInput.getBytes(StandardCharsets.UTF_8));
String encodedString = new String(encodedBytes);
解码:
byte[] decodedBytes = base64.decode(encodedString.getBytes(StandardCharsets.UTF_8));
String decodedString = new String(decodedBytes, StandardCharsets.UTF_8);
3.3 静态方法(推荐)
更简洁的方式是使用静态工具方法,无需创建实例:
String originalInput = "test input";
// 编码
String encodedString = new String(Base64.encodeBase64(originalInput.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
// 解码
byte[] decodedBytes = Base64.decodeBase64(encodedString.getBytes(StandardCharsets.UTF_8));
String decodedString = new String(decodedBytes, StandardCharsets.UTF_8);
✅ 静态方法线程安全,性能更好,推荐日常使用。
4. String 与 byte[] 转换技巧
Base64 处理的是字节数组,因此 String 与 byte[] 的转换是关键。
4.1 普通字符串转 byte[]
String originalInput = "test input";
byte[] result = originalInput.getBytes(StandardCharsets.UTF_8); // ✅ 推荐
⚠️ 避免使用无参 getBytes()
,它依赖系统默认编码,可能引发乱码。
4.2 Base64 字符串解码为 byte[]
String base64String = "dGVzdCBpbnB1dA==";
byte[] result = Base64.getDecoder().decode(base64String);
String decoded = new String(result, StandardCharsets.UTF_8);
4.3 使用 JAXB 的 DatatypeConverter(已弃用)
⚠️ 注意:javax.xml.bind.DatatypeConverter
在 Java 9+ 中已标记为弃用,不推荐新项目使用。
// ❌ 不推荐,仅用于兼容老代码
String base64String = "dGVzdCBpbnB1dA==";
byte[] result = DatatypeConverter.parseBase64Binary(base64String);
// 十六进制转 byte[]
String hexString = "7465737420696E707574";
byte[] hexBytes = DatatypeConverter.parseHexBinary(hexString);
✅ 新项目建议使用 java.util.HexFormat
(Java 17+)或 Commons Codec 的 Hex
类。
5. 总结
方式 | 适用场景 | 推荐指数 |
---|---|---|
java.util.Base64 |
Java 8+ 项目,标准需求 | ✅✅✅✅✅ |
Base64.getUrlEncoder() |
URL/Token 场景 | ✅✅✅✅✅ |
Base64.getMimeEncoder() |
邮件、大文本 | ✅✅✅✅ |
Apache Commons Codec | 老项目、需自定义控制 | ✅✅✅✅ |
DatatypeConverter |
老系统兼容 | ⚠️ 不推荐 |
📌 核心建议:
- ✅ Java 8+ 优先使用原生
Base64
类 - ✅ 显式指定字符集(
UTF-8
) - ✅ URL 场景使用
getUrlEncoder()
- ✅ 避免使用已弃用的
DatatypeConverter
所有示例代码已上传至 GitHub:https://github.com/example/java-base64-demo