HttpMessageNotReadableException: JSON parse error: Unrecognized token '嬀崀'

HttpMessageNotReadableException: JSON parse error: Unrecognized token '嬀崀'

我正在通过 RestTemplate 调用端点,如下所示:

   SSLContext sslContext = SSLContexts.createSystemDefault();
   SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext);
   HttpClient client = HttpClientBuilder.create().setSSLSocketFactory(socketFactory).build();
   ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(client);

   HttpEntity<String> entity = new HttpEntity<>(requestJson, headers());
   Object[] response = restTemplate.postForObject(uri, entity, Object[].class);

我已经验证 entity object 中的 JSON 字符串是有效的,方法是复制它并在对同一端点的 cURL 请求中使用它,没有任何错误。此请求中也使用了相同的 headers 和授权令牌。

当我执行 POST 时,我返回以下错误:

Error while extracting response for type [class [Ljava.lang.Object;] and content type [application/json;charset=utf-16]
org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Unrecognized token '嬀崀': was expecting (JSON String, Number, Array, Object or token 'null', 'true' or 'false'); nested exception is com.fasterxml.jackson.core.JsonParseException: Unrecognized token '嬀崀': was expecting (JSON String, Number, Array, Object or token 'null', 'true' or 'false')
     at [Source: (InputStreamReader); line: 1, column: 3]

我的acceptcontent-typeheaders都设置为application/json。通过检查 cURL 的输出,我发现响应中没有中文字符 body.

回复headers如下:

Connection →keep-alive
Content-Encoding →gzip
Content-Type →application/json; charset=utf-8
Date → xxx
Transfer-Encoding →chunked
Vary →Accept-Encoding

当我请求responseType设置为String.classObject.class时,响应是汉字:

restTemplate.postForObject(uri, entity, String.class);
嬀崀

我希望这个调用 return 一个空数组 []

当我将 requestJson 字符串更改为应该返回 non-empty 数组的字符串时,我得到了数百个汉字,而不是两个。

我如何像使用 cURL 一样解码响应以获得有效数据?

编辑:

我不确定这有什么关系,但是空数组[]中字符的字节码是91和93,这两个汉字的字节码是0、91、0, 93.

restTemplate 的响应似乎是一个汉字字符串而不是一个数组。您发布的第一个错误似乎表明问题出在将响应提取到 Object[] 中。如果来自 restTemplate 的响应实际上是一个字符串,那么这也可以解释第二个错误。 RestTemplate 期望解析一个数组,但却收到了字符串 嬀崀。这就是将响应类型更改为 String.class 似乎有效的原因。

如果您希望从您呼叫的 api 返回一个 JSON 数组,那么我会仔细检查您呼叫的 api 的响应。否则,我建议改用 String.class

已编辑: 有可能 restTemplate 正在使用 utf-16 字符集解析响应,而服务器正在使用 utf-8 字符集对响应进行编码。就像您在描述中发布的那样,这些字符似乎具有相同的字节码。也许将 restTemplate 中的预期字符集更改为 utf-8 将解决您的问题。

不要使用UTF16。 HTTP 规范说 ASCII,许多使用 UTF8。该错误用 charset=utf-16 指出了这一点。尝试根据请求设置编码 header。

正如您在字符代码中指出的那样,您所看到的正是使用 UTF16 时预期的结果,因为每个字符都是 2 个字节。

当我从 cURL 调用它时,API 返回 UTF-8 内容,但是当我以编程方式调用 API 时,尽管我提出请求,它仍然返回 UTF-16LE headers 明确要求 UTF-8。

我需要做一些 de-/en-coding 游戏,但以下内容让我能够观察到有效的预期响应 JSON:

ResponseEntity<byte[]> responseEntity = restTemplate.postForEntity(uri, entity, byte[].class);
   
byte[] bytes = responseEntity.getBody();

String json = new String(bytes, StandardCharsets.UTF_16LE);

FooBar[] fooBar = objectMapper.readValue(json, FooBar[].class);