PowerShell中ConvertFrom-Json编码特殊字符问题

4

我在我的PowerShell脚本中有这段代码,但是它无法处理特殊字符的部分。

 $request = 'http://151.80.109.18:8082/vrageremote/v1/session/players'
 $a = Invoke-WebRequest -ContentType "application/json; charset=utf-8" $request |
 ConvertFrom-Json    |
 Select -expand Data |
 Select -expand players |
 Select displayName, factionTag | Out-file "$scriptPath\getFactionTag.txt"

在我的输出文件中,任何特殊字符都只显示为'????'。有人知道如何让它在我的输出文件中显示特殊字符吗?

3个回答

15

Peter Schneider的有用回答Nas的有用回答都解决了你的方法中的一个问题:你需要:

  • 要么:访问由Invoke-WebRequest返回的响应对象上的.Content属性以获取实际返回的数据(作为JSON字符串),然后将其传递给ConvertFrom-Json

  • 要么:改用Invoke-RestMethod,它会直接返回数据并将其解析为自定义对象,因此您可以直接使用这些对象而无需使用ConvertTo-Json;但是,在像本例中出现字符编码问题时,这不是一个选项,因为需要显式重新编码JSON字符串-请参见下文。

然而,您仍然存在一个字符编码问题,因为在响应头中缺少charset信息的情况下,PowerShell将解释返回的UTF-8编码的JSON字符串为ISO-8859-1编码,在Windows PowerShell以及PowerShell (Core) v7.3.3之前的版本中,除了v7.0+默认使用UTF-8进行JSON
v7.4+将使用UTF-8作为所有媒体类型的通用默认值

有两种可能的解决方案:

  • 最好修改Web服务,将charset=utf-8包含在响应头的ContenType字段中。

  • 如果您无法这样做,您必须根据响应正文的原始字节(通过.RawContentStream属性访问)执行自己的解码:

以下是后者的实现:

# Note that there's no point in using 
# -ContentType  "application/json; charset=utf-8" in this case,
# as -ContentType only applies to data sent *to* the web service.
$request = 'http://151.80.109.18:8082/vrageremote/v1/session/players'
$a = Invoke-WebRequest $request

# $a.Content cannot be used, because it contains the *misinterpreted* JSON string,
# but $a.RawContentStream provides access to the raw bytes,
# which you can decode into a string with the encoding of choice.
$jsonCorrected = 
  [Text.Encoding]::UTF8.GetString(
    $a.RawContentStream.ToArray()
  )

# Now process the reinterpreted string.
$jsonCorrected |
  ConvertFrom-Json    |
  Select -expand Data |
  Select -expand players |
  Select displayName, factionTag | Out-file "$scriptPath\getFactionTag.txt"

注意:

  • 这个答案提供了方便的函数ConvertTo-BodyWithEncoding,它封装了上述的功能。

4
如果您只需要JSON数据而不需要ParsedHtmlHeaders和其他由Invoke-WebRequest返回的对象,则请使用Invoke-RestMethod
$request = 'http://151.80.109.18:8082/vrageremote/v1/session/players'
$a = Invoke-RestMethod -ContentType "application/json; charset=utf-8" $request |
Select -expand Data |
Select -expand players |
Select displayName, factionTag | Out-file "$scriptPath\getFactionTag.txt"

与上面的结果相同,这样可以消除“????”字符,但现在我还剩下很多“Д。比如,“УРА”变成了“УРД。 - user1425462
这是一般情况下有用的建议,但问题在于字符编码,因此需要在进一步处理之前对接收到的字符串数据进行显式重新编码,所以在这种特殊情况下需要使用Invoke-WebRequest响应的.Content属性来进行操作。 - mklement0
1
我曾尝试在我的Invoke-RestMethod调用的头对象中使用-ContentType“application/json; charset=utf-8”,但它没有起作用,将其作为单独的参数传递给Invoke-RestMethod -ContentType“application/json; charset=utf-8”则完美地解决了问题。 - Shrikant Prabhu

2
尝试将 .Content 属性的值转换为 JSON 格式:
$request = 'http://151.80.109.18:8082/vrageremote/v1/session/players'
$a = Invoke-WebRequest -ContentType "application/json; charset=utf-8" $request

($a.Content | convertfrom-json).Data.Players | select DisplayName,FactionTag | Out-file "$scriptPath\getFactionTag.txt" -Encoding Default

这样可以去掉“????”字符,但现在我留下了很多“Д。例如,“УРА”变成了“УРД。 - user1425462

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接