
C# 与 Java 的 Base64 编码结果不同,并非编码逻辑问题,而是 JSON 序列化行为差异所致:Java 的 JSONObject.toString() 默认对 URL 中的 / 进行转义(生成 \/),而 .NET 的 System.Text.Json.JsonSerializer 默认不转义斜杠,导致原始字节数组不同,最终 Base64 结果不一致。
c# 与 java 的 base64 编码结果不同,并非编码逻辑问题,而是 json 序列化行为差异所致:java 的 `jsonobject.tostring()` 默认对 url 中的 `/` 进行转义(生成 `\/`),而 .net 的 `system.text.json.jsonserializer` 默认不转义斜杠,导致原始字节数组不同,最终 base64 结果不一致。
要使 C# 生成与 Java 完全一致的 Base64 字符串,关键在于让两者序列化出完全相同的 JSON 字符串——包括引号、空格、斜杠转义等每一个字符。
? 根本原因分析
- Java 中 new JSONObject().toString() 内部使用了严格的 JSON 规范实现(如 org.json 库),默认对 U+002F(/)进行转义,输出为 https:\/\/test.com\/...;
- C# 中 JsonSerializer.Serialize() 默认不转义斜杠(这是性能优化,默认行为符合 RFC 7159,因为 / 在 JSON 字符串中无需转义),输出为 https://test.com/...;
- 尽管二者解码后语义等价,但字节层面不同(例如 \/ 是两个字节 \ + /,而 / 仅一个字节),因此 Base64 编码必然不同。
✅ 解决方案:在 C# 中启用斜杠转义
使用 JsonSerializerOptions 配置 EscapeHtml = false(默认已为 false,不影响 /)并显式启用斜杠转义——但注意:System.Text.Json 原生不支持仅转义 /。因此需改用兼容性更强的 Newtonsoft.Json(Json.NET),或手动预处理(不推荐)。推荐方案如下:
✅ 方案一:使用 Newtonsoft.Json(推荐,行为最接近 org.json)
// 安装包:Install-Package Newtonsoft.Json
using Newtonsoft.Json;
var claimSets = new Dictionary<string, object>
{
{ "partnerUrl", "https://test.com/testapply/abc/signup" }
};
// Newtonsoft 默认对 '/' 转义(与 org.json 行为一致)
string claimSetsJson = JsonConvert.SerializeObject(claimSets);
byte[] bytes = Encoding.UTF8.GetBytes(claimSetsJson);
string base64 = Convert.ToBase64String(bytes);
// 输出:eyJwYXJ0bmVyVXJsIjoiaHR0cHM6XC9cL3Rlc3QuY29tXC90ZXN0YXBwbHlcL2FiY1wvc2lnbnVwIn0=
Console.WriteLine(base64);✅ 方案二:强制 System.Text.Json 转义斜杠(.NET 6+)
从 .NET 6 开始,JsonSerializerOptions 支持自定义 JavaScriptEncoder。可构造一个强制转义 / 的编码器:
using System.Text.Encodings.Web;
using System.Text.Json;
var encoder = JavaScriptEncoder.Create(
UnicodeRanges.All, // 包含所有范围
'/'); // 显式添加 '/' 到需转义字符列表
var options = new JsonSerializerOptions
{
Encoder = encoder,
WriteIndented = false
};
string claimSetsJson = JsonSerializer.Serialize(claimSets, options);
byte[] bytes = Encoding.UTF8.GetBytes(claimSetsJson);
string base64 = Convert.ToBase64String(bytes);⚠️ 注意:JavaScriptEncoder.Create(...) 的第二个参数是「额外需转义的字符」,传入 '/' 即可生效。
? 验证一致性
将 Java 输出的 Base64 字符串 eyJwYXJ0bmVyVXJsIjoiaHR0cHM6XC9cL3Rlc3QuY29tXC90ZXN0YXBwbHlcL2FiY1wvc2lnbnVwIn0= 与 C# 上述任一方案输出对比,二者将完全相同。
? 总结
- Base64 编码本身无语言差异,差异永远源于输入字节数组是否一致;
- JSON 序列化库的行为(如斜杠转义、空白符、键序等)必须统一;
- 生产环境中涉及跨语言 JWT、JWT ClaimSet 或签名载荷时,建议:
- 固定 JSON 库版本(如 Java 用 org.json:json:20231013,C# 用 Newtonsoft.Json:13.0.3);
- 在单元测试中加入跨语言 Base64 对照断言;
- 避免依赖默认行为,显式配置序列化选项。
统一序列化输出,才能保证 Base64 的确定性与互操作性。


















