➜ Old React website
Chung Cheuk Hang MichaelJava Web Developer
Remote debug Java 程式Spring 項目使用 ELK 做 logging

Spring JSON 變 XML response 問題

Table of contents

1 背景

有某一個 Spring Boot 2 既 web application 唔知點解有個 HTTP POST API 喺唔同情況下,有時會返回 JSON 或者 XML 格式既 responses,而 XML 格式就會導致 consumer application 喺 deserialize 個 response 既時候出現 deserialization exception。
情況Response 格式
使用 Postman 直接 call 個 APIJSON
喺 cloud provider 平台上面 test 個 APIJSON
Consumer application 喺 cloud 既環境下用 Spring 既 RestTemplate call 個 APIXML
Postman 既 call 法係用默認既 Postman HTTP request headers,Accept request header 係 */*
Cloud provider 平台既 call 法係冇任何 HTTP request headers。
Consumer application 用既係 RestTemplate#exchange method 去 call 呢個 HTTP POST API,而 HttpEntity 既 request body 係 nullHttpHeadersnew HttpHeaders(),冇咩特別。

2 原因分析

2.1 Cloud provider API 配置

Cloud provider 既平台上面冇任何配置,冇對 HTTP API response 做 conversion 或者改 request header,所以唔關 cloud config 事。

2.2 Maven dependencies

如果只係得 spring-boot-starter-web 呢個 dependency,係冇能力返回 XML 格式既。
查下 Spring 既文檔就發現到原來 producer application 以及 consumer application 都有以下既 transitive dependency:
<dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> </dependency>
加左呢個 dependency 之後:
  • Application 會有能力返回 XML 格式既 HTTP responses。
    • 不過就唔會自動將所有 exposed 既 APIs(Spring 既 request mappings)默認返回 XML 格式。
  • Application 會有能力解讀 XML 格式既 HTTP responses(但唔清楚點解 consumer application 會出現 deserialization exception)。
  • 會令到我地冇特別配置既 RestTemplate 既 HTTP requests 既 Accept request header 用左 application/xml 等等既 values,咁就會令到 producer application 傾向選擇返回 XML 格式既 HTTP responses,而咁岩 producer application 又有能力咁做。
咁就解釋到點解 Postman 以及 cloud provider 平台上面測試果陣冇得到 XML 格式既 HTTP responses。
參考資料:

3 解決方法

只需要將 RestTemplate object 既 XML message converter 移除就可以,咁喺 call HTTP APIs 既時候,就唔會喺 Accept request headers 裡面加入 application/xml 等等既 values。
1@Bean 2public RestTemplate restTemplate() { 3 final RestTemplate restTemplate = new RestTemplate(); 4 restTemplate.getMessageConverters().removeIf(MappingJackson2XmlHttpMessageConverter.class::isInstance); 5 6 return restTemplate; 7}
參考資料: