PowerShell Invoke-RestMethod Umlauts проблемы с UTF-8 и Windows-1252 - PullRequest
0 голосов
/ 24 октября 2019

После выполнения вызовов API REST Confluence я получаю ответ, закодированный в UTF-8. Однако при экспорте результатов с Out-File или Export-CSV даже с параметром -Encoding utf8 немецкие умлауты отображаются неправильно. Например, «ü» все еще «Ã¼».

Из того, что я мог понять, это связано с тем, что PowerShell 5.1 изначально использует Windows-1252. Я проверил, что Umlauts сохраняются при использовании PowerShell Core, выполнив

[psobject].Assembly.GetTypes() | Where-Object { $_.Name -eq 'ClrFacade'} | ForEach-Object { $_.GetMethod('GetDefaultEncoding', [System.Reflection.BindingFlags]'nonpublic,static').Invoke($null, @()) }

Даже изменение самого файла сценария для использования кодировки UTF-8 с BOM или Windows-1252 не сохраняет Umlauts, ни в PowerShell, ни в выводе exportet.

Известны ли вам какие-либо способы заставить PowerShell 5.1 сохранять Umlauts при выполнении вызова REST?

Я не могу использовать ядро ​​PowerShell, поскольку для дальнейших операций требуются командлетыкоторые еще не созданы для PowerShell Core.

Спасибо!

1 Ответ

1 голос
/ 24 октября 2019

Как обсуждалось в комментариях, похоже, что Confluence API кодирует HTTP-ответы с использованием UTF8, но не включает заголовок "Content-Type", чтобы указать, что.

HTTPспецификация параметра charset гласит, что при отсутствии этого заголовка клиент должен предполагать, что он закодирован с набором символов ISO-8859-1, так что то, что происходит в вашем запросе, выглядит примерно так:

# server (Confluence API) encodes response text using utf8
PS> $text = "ü";
PS> $bytes = [System.Text.Encoding]::UTF8.GetBytes($text);
PS> write-host $bytes;
195 188

# client (Invoke-RestMethod) decodes bytes as ISO-8859-1
PS> $text = [System.Text.Encoding]::GetEncoding("ISO-8859-1").GetString($bytes);
PS> write-host $text;
ü

Учитывая, что вы не можете контролировать то, что отправляет сервер, вам нужно либо самостоятельно захватить необработанные байты (например, используя System.Net.Http.HttpClient ) и декодировать их, используяUTF8 или измените существующий ответ, чтобы компенсировать несоответствие кодировки (например, ниже).

PS> $text = "ü"
PS> $bytes = [System.Text.Encoding]::GetEncoding("ISO-8859-1").GetBytes($text)
PS> $text = [System.Text.Encoding]::UTF8.GetString($bytes)
PS> write-host $text
ü

Обратите внимание, что если вы используете параметр -Outfile в Invoke-RestMethod, он, предположительно, передает потоковые байты ответа непосредственно на диск. без декодирования или кодирования, поэтому результирующий файл уже содержит utf8 $bytes, а не utf8 $bytes -> string decoded using ISO-8859-1 -> file bytes encoded using utf8

...