我正在PowerShell7.4中创建一个JSON文件,以发送到第三方REST端点.Out-File默认为UTF-8,当我在notepad++ 中判断文件时,编码设置显示为UTF-8.不幸的是,这篇帖子被拒绝了,并发了一条消息:

400 Bad Request
JSON parse error
Nested exception is com.fasterxml.jackson.databind.JsonMappingException: Invalid UTF-8 start byte 0xa0\n at line: 9259, column: 38

我判断了错误消息中指定的JSON行. 源JSON文件在其公司名称中有一个NO-BREAK SPACE序列,如下所示:

String        Hex
------------  --------------------------------------
"Acme, Inc."  22 41 63 6d 65 2c c2 a0 49 6e 63 2e 22

UTF-8中的NO-BREAK SPACE显示为两个字节:0xc2 0xa0.这两个字符都出现在JSON文件中,但该错误表明远程解析器没有将第一个字符作为序列的一部分进行处理.

以下是PowerShell脚本:

# identify CSV file

   $csvFile = Get-ChildItem -Path ($path + '*.csv') -File | 
                 Sort-Object LastWriteTime | 
                 Select-Object -First 1 

# suppress blank lines

   $objData = Get-Content $csvFile -Encoding UTF8 | 
                 Where-Object { $_ } | 
                 ConvertFrom-CSV

# convert to JSON and save to file
     
   $body = $objData | 
              ConvertTo-Json -Depth 100

   $body | 
      Out-File ( $path + 'data.json')
        
# post JSON

    $webParam = @{
       Uri         = $url 
       Method      = 'POST' 
       Headers     =  @{ 'Authorization' = $auth
                         'Cache-Control' = 'no-cache' }
       Body        = $body 
       ContentType = 'application/json'
    }
  
$apiResponse = Invoke-WebRequest @webParam

每次脚本运行时,数据通常都不同. 在大多数情况下,远程站点将毫无问题地接受JSON,因为它没有任何奇怪的Unicode字符.

我不确定为什么远程站点不喜欢这个字符串,但如果它不能区分整个两个字节的序列,那么这个错误是有意义的.在我发送之前,PowerShell的Test-JSON cmdlet总是计算为True.以前有没有人遇到过这种情况?

推荐答案

To ensure that PowerShell uses UTF-8 encoding also in versions 7.3.x and below (including Windows PowerShell) when it transmits the .NET string passed to the -Body parameter of Invoke-WebRequest, use
-ContentType 'application/json; charset=utf-8' (in PowerShell 7.4+, this is no longer necessary); applied to your splatting scenario:

    $webParam = @{
       Uri         = $url 
       Method      = 'POST' 
       Headers     =  @{ 'Authorization' = $auth
                         'Cache-Control' = 'no-cache' }
       Body        = $body 
       # Note the addition of '; charset=utf-8'
       ContentType = 'application/json; charset=utf-8'
    }
  
$apiResponse = Invoke-WebRequest @webParam
  • 您最初从UTF-8文件中读取文本在这种情况下是无关紧要的,因为通过使用.NET字符串,您将使用什么字符编码的决定委托给Invoke-WebRequest,而在7.4之前的版本中,编码是ISO-8559-1

    • 在这single-byte编码中,不间断空格(U+00A0)字符的码位是0xa alone--这相当于编码一个非ASCII字符的illegal start byte of a multi-byte UTF-8 sequence--这就是您的目标服务器所抱怨的.

    • 事实上,因为ISO-8559-1构成了Unicode8-bit subrange,并且由于UTF-8 Unicode编码的工作方式,所以0x80-0xbf范围内的所有Unicode代码点都是two-byte序列,其第一个字节是0xc2,后跟一个带有same value as the code point的字节.

    • Thus, NO-BREAK SPACE (U+00A0) - the character whose code point is 0xa0 in both Unicode (abstractly) and ISO-8559-1 (as a concrete, single-byte value) - is the two-byte sequence 0xc2 0xa0 in UTF-8.
      Because, due to mistaken ISO-8559-1 encoding, only 0xa0 was transmitted, it appeared as if the target server ignored the 0xc2, but in actuality it never received it.

  • 有关PowerShell行为的其他信息,请参阅this answer(同样适用于Invoke-RestMethod小工具).

Json相关问答推荐

Jolt转换问题—使用键查找匹配对象

使用更高级别架构中的字段值在$def内实现约束

如何使用PlayWriter循环访问JSON对象

如何使用PowerShell从ExchangeOnline命令执行中获得JSON输出

419(未知状态)使用laravel处理PUT请求

jq 对特定键进行过滤并将值整理到单个 csv 单元格中

正向闪烁后的微调值

遍历 JSON,检索父值

使用 jq 将消息转换为数组

将请求中的数据推送到数组中

如何将该 JSON 解析为 Kotlin 类?

JOLT JSON 将值从一对多转换为一对一

嵌套 JSON 到 CSV(多级)

JQuery,使用 GET 方法发送 JSON 对象

将 js Array() 转换为 JSON 对象以用于 JQuery .ajax

Python - 如何将 JSON 文件转换为数据框

将json字符反序列化为枚举

如何在已声明的 JSON 对象中添加键值对

如何使用 Json.NET 反序列化可以是两种不同数据类型的 JSON 属性

如何在所有子项中查询具有特定值的属性的firebase