共用方式為


如何使用 System.Text.Json 自訂字元編碼

根據預設,序列化程式會逸出所有非 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 版本中都會變更的實作詳細資料。 請勿依賴屬於全域封鎖清單成員 (或不是成員) 的字元。

編碼器專用的封鎖清單

編碼器專用封鎖字碼指標的範例包括 HTML 編碼器'<''&'JSON 編碼器'\',以及 URL 編碼器'%'。 例如,即使 & 符號位於 BasicLatin 範圍中,而且所有編碼器都預設透過 BasicLatin 初始化,HTML 編碼器仍然一律會逸出 & 符號 ('&')。

序列化所有字元

若要將轉譯降至最低,您可以使用 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> 元素。

另請參閱