【问题标题】:PowerShell Invoke-RestMethod Umlauts issues with UTF-8 and Windows-1252UTF-8 和 Windows-1252 的 PowerShell Invoke-RestMethod 变音符号问题
【发布时间】:2019-10-24 22:18:47
【问题描述】:

在执行 Confluence REST API 调用时,我会返回一个以 UTF-8 编码的响应。但是,当我使用Out-FileExport-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 核心中。

谢谢!

【问题讨论】:

  • 你可以试试-Outfile参数吗?
  • 您知道您工作流程的哪一部分破坏了编码吗?例如它绝对是invoke-restmethod,还是out-file或您正在检查文件内容的查看器?例如,如果我这样做"ü" | out-file c:\temp\umlaut-utf8.txt -encoding utf8,我会得到一个字节为“EF BB BF C3 BC 0D 0A”的文件,该文件在记事本中显示“ü”,但在十六进制编辑器中显示“ü”。
  • @AdminOfThings,您的建议确实保留了元音变音,这很好。但是,我注意到它仅在指定 .txt 扩展名时才会这样做。 .csv 在这里也不起作用。最终,我希望将 REST 响应详细信息存储在 CSV 文件中。
  • @mclayton,我怀疑它是外壳,即 PowerShell 5.1。在 VSCode 中(但 powershell.exe 在独立模式下的行为也相同)。我猜"ü" | out-file 之所以有效,是因为它不像在执行 cmdlet 时那样首先被外壳“内部化”。所以概括地说,每个变音符号都由 PS 5.1 中的 cmdlet 处理。应该会出现编码问题。
  • 你有一个简单的复制品我可以在这里试试吗?我在 powershell.exe 控制台中尝试过,但文件在记事本中显示变音符号正常:$xmldoc = Invoke-RestMethod -Uri "https://en.wikipedia.org/wiki/%C3%9C"; $xmldoc.DocumentElement.InnerText | out-file c:\temp\out.txt -Encoding utf8;

标签: powershell rest encoding utf-8 windows-1252


【解决方案1】:

正如 cmets 中所讨论的,看起来 Confluence API 使用 UTF8 对 http 响应进行编码,但包含“Content-Type”标头来表明这一点。

charset parameter 的 HTTP 规范说,在没有此标头的情况下,客户端应假定它是使用 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-21
    相关资源
    最近更新 更多