首页 > 编程语言 >Base64编码结果不一致的根源:JSON序列化斜杠转义差异

Base64编码结果不一致的根源:JSON序列化斜杠转义差异

来源:互联网 2026-07-14 08:07:06

C#与Java的Base64编码结果差异,源自JSON序列化时斜杠转义规则不同:Java默认转义斜杠,C#默认不转义。统一序列化规则,例如C#使用Newtonsoft.Json或配置System.Text.Json转义斜杠,即可使Base64结果一致。因为Base64编码中可能包含正斜杠字符,而Java会将其转义,导致差异,统一后即可解决。此方法可有效解决跨

C# 与 Ja va 的 Base64 编码结果不同,并非编码逻辑本身出了问题,而是 JSON 序列化时的行为差异在“捣鬼”。简单来说,Ja va 的 JSONObject.toString() 默认会对 URL 中的斜杠 / 进行转义,生成 \/;而 .NET 的 System.Text.Json.JsonSerializer 则默认不转义斜杠。这可不仅仅是写法不同,它直接导致原始字节数组不一样,Base64 结果自然也就大相径庭。

那么,怎样才能让 C# 和 Ja va 生成一模一样的 Base64 字符串呢?关键在于,让两者序列化出完全相同的 JSON 字符串——从引号、空格到斜杠转义,每一个字符都要对得上。

根本原因分析

问题出在哪儿?其实就两点:

长期稳定更新的攒劲资源: >>>点此立即查看<<<

  • Ja va 的 new JSONObject().toString(),内部实现遵循了更严格的 JSON 规范(比如 org.json 库),默认会对 U+002F(也就是 /)进行转义,输出结果类似 https:\/\/test.com\/...
  • C# 的 JsonSerializer.Serialize() 则走了另一条路,它默认不转义斜杠。这其实是一种性能优化,而且符合 RFC 7159 标准(因为 / 在 JSON 字符串中本身不是必须转义的字符),所以输出就是 https://test.com/...

关键在于,这两种写法虽然解码后语义完全等价,但在字节层面是不同的。比如,\/ 是两个字节(反斜杠和斜杠),而 / 只是一个字节。因此,Base64 编码的结果必然无法统一。

解决方案:在 C# 中启用斜杠转义

既然知道了原因,解决方案就明朗了。我们需要让 C# 的序列化行为与 Ja va 保持一致,也就是强制对斜杠进行转义。

不过要留意的是,System.Text.Json 在默认情况下,并没有提供直接开关来“仅针对斜杠进行转义”。因此,最直接、最稳妥的方式是换用兼容性更强的 Newtonsoft.Json(也就是 Json.NET)。当然,如果你必须使用 System.Text.Json,也有办法,只是需要额外配置。

方案一:使用 Newtonsoft.Json(推荐,行为最接近 org.json)

这个方案最为简单直接,因为 Newtonsoft.Json 默认就对斜杠进行转义,和 Ja va 的 org.json 库行为一致。

// 安装包:Install-Package Newtonsoft.Json
using Newtonsoft.Json;

var claimSets = new Dictionary
{
    { "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+)

如果你希望继续使用 System.Text.Json,从 .NET 6 开始,可以通过自定义 Ja vaScriptEncoder 来实现。核心思路是,创建一个编码器,把斜杠 / 加入到“需要额外转义的字符”列表中。

using System.Text.Encodings.Web;
using System.Text.Json;

var encoder = Ja vaScriptEncoder.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);

注意:Ja vaScriptEncoder.Create(...) 的第二个参数是“额外需转义的字符”,把 '/' 传进去即可生效。

验证一致性

将 Ja va 输出的 Base64 字符串(例如 eyJwYXJ0bmVyVXJsIjoiaHR0cHM6XC9cL3Rlc3QuY29tXC90ZXN0YXBwbHlcL2FiY1wvc2lnbnVwIn0=)与 C# 任意一个方案输出的结果进行对比,你会发现它们完全一致。

总结

  • Base64 编码本身是没有语言差异的,差异永远源于输入字节数组是否一致
  • JSON 序列化库的行为(如斜杠转义、空白符、键序等)必须统一,这是跨语言协作的基础。
  • 在生产环境中,涉及跨语言的 JWT、JWT ClaimSet 或签名载荷时,建议:
    • 固定 JSON 库的版本(例如 Ja va 用 org.json:json:20231013,C# 用 Newtonsoft.Json:13.0.3)。
    • 在单元测试中加入跨语言的 Base64 对照断言,提前发现问题。
    • 避免依赖默认行为,显式配置序列化选项,确保行为一致。

统一序列化输出,才能保证 Base64 的确定性与互操作性。这不仅是技术细节,更是跨语言协作的工程实践。

侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述

热游推荐

更多
湘ICP备14008430号-1 湘公网安备 43070302000280号
All Rights Reserved
本站为非盈利网站,不接受任何广告。本站所有软件,都由网友
上传,如有侵犯你的版权,请发邮件给xiayx666@163.com
抵制不良色情、反动、暴力游戏。注意自我保护,谨防受骗上当。
适度游戏益脑,沉迷游戏伤身。合理安排时间,享受健康生活。