PowerShell Invoke-RestMethod UTF-8 和 Windows-1252 变音问题
PowerShell Invoke-RestMethod Umlauts issues with UTF-8 and Windows-1252
执行 Confluence REST API 调用后,我得到一个以 UTF-8 编码的响应。但是,当我使用 Out-File
或 Export-CSV
导出结果时,即使使用 -Encoding utf8
参数也无法正确表示德语变音符号。例如,'ü' 仍然是 'ϼ'。
据我所知,这是因为 PowerShell 5.1 本身依赖于 Windows-1252。我通过执行
[psobject].Assembly.GetTypes() | Where-Object { $_.Name -eq 'ClrFacade'} |
ForEach-Object {
$_.GetMethod('GetDefaultEncoding', [System.Reflection.BindingFlags]'nonpublic,static').Invoke($null, @())
}
验证了在使用 PowerShell Core 时保留了变音符号
即使更改脚本文件本身以使用带 BOM 或 Windows-1252 的编码 UTF-8 也不会保留变音符号,无论是在 PowerShell 还是 exportet 输出中。
您知道有什么方法可以让 PowerShell 5.1 在执行 REST 调用时保留变音符号吗?
我无法使用 PowerShell 核心,因为进一步的操作需要 cmdlet,而这些 cmdlet 确实存在于 PowerShell 核心。
谢谢!
正如评论中所讨论的,看起来 Confluence API 使用 UTF8 编码 http 响应,但 不 包含 "Content-Type" header 表示。
charset parameter 的 HTTP 规范说,如果没有这个 header,客户端应该假设它是用 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
ü
请注意,如果您使用 Invoke-RestMethod 的 -Outfile
参数,它可能会将响应字节直接流式传输到磁盘而不对其进行解码或编码,因此生成的文件已经包含 utf8 $bytes
而不是比 utf8 $bytes -> string decoded using ISO-8859-1 -> file bytes encoded using utf8
执行 Confluence REST API 调用后,我得到一个以 UTF-8 编码的响应。但是,当我使用 Out-File
或 Export-CSV
导出结果时,即使使用 -Encoding utf8
参数也无法正确表示德语变音符号。例如,'ü' 仍然是 'ϼ'。
据我所知,这是因为 PowerShell 5.1 本身依赖于 Windows-1252。我通过执行
[psobject].Assembly.GetTypes() | Where-Object { $_.Name -eq 'ClrFacade'} |
ForEach-Object {
$_.GetMethod('GetDefaultEncoding', [System.Reflection.BindingFlags]'nonpublic,static').Invoke($null, @())
}
即使更改脚本文件本身以使用带 BOM 或 Windows-1252 的编码 UTF-8 也不会保留变音符号,无论是在 PowerShell 还是 exportet 输出中。
您知道有什么方法可以让 PowerShell 5.1 在执行 REST 调用时保留变音符号吗?
我无法使用 PowerShell 核心,因为进一步的操作需要 cmdlet,而这些 cmdlet 确实存在于 PowerShell 核心。
谢谢!
正如评论中所讨论的,看起来 Confluence API 使用 UTF8 编码 http 响应,但 不 包含 "Content-Type" header 表示。
charset parameter 的 HTTP 规范说,如果没有这个 header,客户端应该假设它是用 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
ü
请注意,如果您使用 Invoke-RestMethod 的 -Outfile
参数,它可能会将响应字节直接流式传输到磁盘而不对其进行解码或编码,因此生成的文件已经包含 utf8 $bytes
而不是比 utf8 $bytes -> string decoded using ISO-8859-1 -> file bytes encoded using utf8