如何使用 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>
元素。