默认情况下,序列化程序会转义所有非 ASCII 字符。 即,会将它们替换为 \uxxxx ,其中 xxxx 为字符的 Unicode 代码。 例如,如果以下 JSON 中的 Summary 属性设置为西里尔文 жарко ,则 WeatherForecast 对象会进行序列化,如以下示例中所示:

"Date": "2019-08-01T00:00:00-07:00", "TemperatureCelsius": 25, "Summary": "\u0436\u0430\u0440\u043A\u043E"

序列化语言字符集

若要序列化一种或多种语言的字符集而不进行转义,请在创建 System.Text.Encodings.Web.JavaScriptEncoder 的实例时指定 Unicode 范围 ,如以下示例中所示:

using System.Text.Encodings.Web; using System.Text.Json; using System.Text.Unicode; Imports System.Text.Encodings.Web Imports System.Text.Json Imports System.Text.Unicode var options1 = new JsonSerializerOptions Encoder = JavaScriptEncoder.Create(UnicodeRanges.BasicLatin, UnicodeRanges.Cyrillic), WriteIndented = true jsonString = JsonSerializer.Serialize(weatherForecast, options1); options = New JsonSerializerOptions With { .Encoder = JavaScriptEncoder.Create(UnicodeRanges.BasicLatin, UnicodeRanges.Cyrillic), .WriteIndented = True jsonString = JsonSerializer.Serialize(weatherForecast1, options)

此代码不转义西里尔文或希腊语字符。 如果 Summary 属性设置为西里尔文 жарко ,则 WeatherForecast 对象会进行序列化,如以下示例中所示:

"Date": "2019-08-01T00:00:00-07:00", "TemperatureCelsius": 25, "Summary": "жарко"

默认情况下,编码器使用 BasicLatin 范围进行初始化。

若要序列化所有语言集而不进行转义,请使用 UnicodeRanges.All

序列化特定字符

一种替代方法是指定要允许的单个字符,而不进行转义。 下面的示例仅序列化 жарко 的前两个字符:

using System.Text.Encodings.Web; using System.Text.Json; using System.Text.Unicode; Imports System.Text.Encodings.Web Imports System.Text.Json Imports System.Text.Unicode var encoderSettings = new TextEncoderSettings(); encoderSettings.AllowCharacters('\u0436', '\u0430'); encoderSettings.AllowRange(UnicodeRanges.BasicLatin); var options2 = new JsonSerializerOptions Encoder = JavaScriptEncoder.Create(encoderSettings), WriteIndented = true jsonString = JsonSerializer.Serialize(weatherForecast, options2); Dim encoderSettings As TextEncoderSettings = New TextEncoderSettings encoderSettings.AllowCharacters(ChrW(&H436), ChrW(&H430)) encoderSettings.AllowRange(UnicodeRanges.BasicLatin) options = New JsonSerializerOptions With { .Encoder = JavaScriptEncoder.Create(encoderSettings), .WriteIndented = True jsonString = JsonSerializer.Serialize(weatherForecast1, options)

下面是前面代码生成的 JSON 的示例:

"Date": "2019-08-01T00:00:00-07:00", "TemperatureCelsius": 25, "Summary": "жа\u0440\u043A\u043E"

前面的部分显示了如何指定不希望转义的码位或范围的允许列表。 但是,存在一些全局和编码器特定的阻止列表,它们可覆盖允许列表中的某些码位。 阻止列表中的码位总是进行转义,即使它们包含在允许列表中也是如此。

全局阻止列表

全局阻止列表包括专用字符、控制字符、未定义的码位和某些 Unicode 类别(如 Space_Separator 类别 )等内容,但不包含 U+0020 SPACE 。 例如,即使指定 Unicode 范围 CJK 符号和标点 (U+3000-U+303F) 作为允许列表,也会对 U+3000 IDEOGRAPHIC SPACE 进行转义。

全局阻止列表是一个实现细节,在 .NET Core 的每个版本和 .NET 5 中都有所更改。 不要依赖于全局阻止列表中包含(或未包含)的字符。

编码器特定的阻止列表

对于 HTML 编码器 ,编码器特定的阻止列表的示例包括 '<' '&' ;对于 JSON 编码器 ,示例包括 '\' ;对于 URL 编码器 ,示例包括 '%' 。 例如,HTML 编码器总是会转义与号 ( '&' ),即使与号在 BasicLatin 范围内,并且所有编码器都默认使用 BasicLatin 进行初始化。

序列化所有字符

若要最大程度地减少转义,可以使用 JavaScriptEncoder.UnsafeRelaxedJsonEscaping ,如以下示例中所示:

using System.Text.Encodings.Web; using System.Text.Json; using System.Text.Unicode; Imports System.Text.Encodings.Web Imports System.Text.Json Imports System.Text.Unicode var options3 = new JsonSerializerOptions Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, WriteIndented = true jsonString = JsonSerializer.Serialize(weatherForecast, options3); options = New JsonSerializerOptions With { .Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, .WriteIndented = True jsonString = JsonSerializer.Serialize(weatherForecast1, options)

与默认编码器相比, UnsafeRelaxedJsonEscaping 编码器在允许字符通过而不进行转义方面更加宽松:

  • 它不转义 HTML 敏感字符,如 < > & '
  • 它不提供任何针对 XSS 或信息泄露攻击(如客户端和服务器在字符集方面不一致所可能导致的攻击)的额外深度防御保护。
  • 仅当知道客户端将生成的有效负载解释为 UTF-8 编码的 JSON 时,才使用不安全编码器。 例如,如果服务器在发送响应标头 Content-Type: application/json; charset=utf-8 ,则可以使用它。 永远不允许将原始 UnsafeRelaxedJsonEscaping 输出发出到 HTML 页面或 <script> 元素。

  • System.Text.Json 概述
  • 如何对 JSON 进行序列化和反序列化
  •