0

我通过 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);

我已经通过将对象中的 JSON 字符串entity复制并在对同一端点的 cURL 请求中使用它而没有任何错误来验证对象中的 JSON 字符串是有效的。此请求中也使用了相同的标头和授权令牌。

当我执行 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]

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

响应头如下:

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

当我使用responseType设置为String.classor发出请求时Object.class,响应是中文字符:

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

我期待这个调用应该返回一个空数组[]

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

如何解码响应以获取有效数据,例如使用 cURL 时?

编辑:

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

4

3 回答 3

0

当我从 cURL 调用 API 时,API 正在返回 UTF-8 内容,但是当我以编程方式调用 API 时,尽管我的请求标头明确要求 UTF-8,但它正在返回 UTF-16LE。

我需要做一些解码/编码游戏,但以下允许我观察有效的、预期的响应 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);
于 2021-04-14T13:54:27.427 回答
0

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

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

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

于 2021-04-13T14:10:13.933 回答
0

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

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

于 2021-04-13T14:38:32.433 回答