Powershell Invoke-WebRequest 和字符编码

Sol*_*lex 2 powershell json character-encoding spotify

我正在尝试通过 Spotify 数据库的 Web API 获取信息。\n但是,我遇到了重音元音问题(\xc3\xa4、\xc3\xb6、\xc3\xbc 等)

\n\n

以 Ti\xc3\xabsto 为例。\nSpotify 的 API 浏览器可以正确显示信息:\n https://developer.spotify.com/web-api/console/get-artist/?id=2o5jDhtHVPhrJdv3cEQ99Z

\n\n

如果我进行 API 调用,Invoke-Webrequest我会得到

\n\n
\n

钛??斯托

\n
\n\n

如名称:

\n\n
function Get-Artist {\nparam($ArtistID = \'2o5jDhtHVPhrJdv3cEQ99Z\',\n      $AccessToken = \'MyAccessToken\')\n\n\n$URI = "https://api.spotify.com/v1/artists/{0}" -f $ArtistID\n\n$JSON = Invoke-WebRequest -Uri $URI -Headers @{"Authorization"= (\'Bearer  \' + $AccessToken)} \n$JSON = $JSON | ConvertFrom-Json\nreturn $JSON\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

在此输入图像描述

\n\n

我怎样才能得到正确的名字?

\n

mkl*_*nt0 8

更新PowerShell(核心) 7.0+现在默认对 JSON 使用UTF-8 ,而在7.4+中,如果 HTTP 响应标头中没有(有效)属性,则通常默认使用UTF -8,因此问题不再出现。 charset


Jeroen Mostert在对该问题的评论中很好地解释了这个问题:

问题是 Spotify(不明智地)没有返回它在标头中使用的编码。PowerShell 通过假设 ISO-8859-1 来遵守[现已过时]标准,但不幸的是该网站使用的是 UTF-8。(PowerShell 应该忽略这里的标准并假定 UTF-8,但这就像我的观点,伙计。)更多详细信息请参见此处,以及后续票证。

不需要使用临时文件的解决方法

手动将响应的原始字节流解码为 UTF-8:

$JSON = 
  [Text.Encoding]::UTF8.GetString(
    (Invoke-WebRequest -Uri $URI ...).RawContentStream.ToArray()
  )
Run Code Online (Sandbox Code Playgroud)

或者,使用便利功能ConvertTo-BodyWithEncoding;假设它已被定义(见下文),您可以更简单地使用以下内容:

# ConvertTo-BodyWithEncoding defaults to UTF-8.
$JSON = Invoke-WebRequest -Uri $URI ... | ConvertTo-BodyWithEncoding
Run Code Online (Sandbox Code Playgroud)

便利功能ConvertTo-BodyWithEncoding

笔记:

  • 该函数手动解码构成给定响应主体的原始字节,默认为 UTF-8,或者使用给定编码,可以指定为实例[System.Text.Encoding]代码页号(例如1251)或编码名称(例如,'utf-16le')。

  • 该功能还可以作为MIT 许可的 Gist提供,并且只有后者将继续得到维护。假设您已经查看了链接的代码以确保它是安全的(我个人可以向您保证,但您应该始终检查),您可以按如下方式直接定义它(有关如何使该函数在将来的会话中可用的说明或将显示将其转换为脚本):

    irm https://gist.github.com/mklement0/209a9506b8ba32246f95d1cc238d564d/raw/ConvertTo-BodyWithEncoding.ps1 | iex
    
    Run Code Online (Sandbox Code Playgroud)
function ConvertTo-BodyWithEncoding {

  [CmdletBinding(PositionalBinding=$false)]
  param(
    [Parameter(Mandatory, ValueFromPipeline)]
    [Microsoft.PowerShell.Commands.WebResponseObject] $InputObject,
    # The encoding to use; defaults to UTF-8
    [Parameter(Position=0)]
    $Encoding = [System.Text.Encoding]::Utf8
  )

  begin {
    if ($Encoding -isnot [System.Text.Encoding]) {
      try {
        $Encoding = [System.Text.Encoding]::GetEncoding($Encoding)
      }
      catch { 
        throw
      }
    }
  }

  process {
    $Encoding.GetString(
       $InputObject.RawContentStream.ToArray()
    )
  }

}
Run Code Online (Sandbox Code Playgroud)