現在來看原先寫的這篇文章,覺得當時將問題想複雜了。目前最簡單的解決方式大概是:
定義接收對象:
@JsonIgnoreProperties(ignoreUnknown = true) // 某字段時爲空不會報錯
@Data
public class LibraryRes {
private String libraryId;
private int errorCode;
private String errorMsg;
private String errorType;
}
更新時間:2020-2-17
以下是原文↓↓↓
- 記錄一下今天遇到的問題,和嘗試解決過程中的經歷 -
在與其他微服務接口進行聯調的過程中,因爲我這邊依賴的接口在正常和異常兩種情況下,返回的字段不一樣,導致我這邊通過restTemplate發送請求時,封裝的返回對象不能夠靈活適配接口返回對象的字段,於是在服務異常返回時,我這邊處理不了。
於是查詢解決這個問題的方法,發現可以自己定義一個ResponseErrorHandler的實現類,對異常情況進行處理。
依賴接口返回參數示例
正常情況:
{
"library_id": "36"
}
異常情況:
{
"error_code": 8008,
"error_msg": "",
"error_type": "library_name is not string"
}
由於依賴接口正常和異常情況下http狀態碼都是200,導致不能通過狀態碼來判斷哪種情況是異常情況,只能通過取body中的值來校驗,寫了如下FaceResponseErrorHandler類。
ResponseErrorHandler的實現類:
public class FaceResponseErrorHandler implements ResponseErrorHandler {
/** 對response進行判斷,如果是異常情況,返回true */
@Override
public boolean hasError(ClientHttpResponse response) throws IOException {
Map map = JSON.parseObject(convertStreamToString(response.getBody()));
return map.containsKey("error_code");
}
/** 異常情況時的處理方法 */
@Override
public void handleError(ClientHttpResponse response) {
throw new LibraryException(FaceErrorCode.IA_LIBRARY_ERROR, FaceResponseErrorHandler.class);
}
/**
* InputStream轉成String
* @param is InputStream
* @return String
*/
private String convertStreamToString(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line;
try {
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
throw BaseException.of(FaceErrorCode.IA_LIBRARY_ERROR.of());
} finally {
is.close();
}
return sb.toString();
}
}
FaceResponseErrorHandler調用:
restTemplate.setErrorHandler(new FaceResponseErrorHandler());
Object res = restTemplate.postForObject(host + IAConstant.LIBRARY_MANAGER, addReqDO, Object.class);
測試後發現,這種方式存在異常報錯或獲取到的res爲Null的問題,原因是在FaceResponseErrorHandler類中convertStreamToString()方法裏讀取數據並轉化之後,在finally裏面將流關閉,導致後續restTemplate原生方法在處理返回值的時候報流已關閉的錯誤,即使將finally代碼去除,由於在convertStreamToString()方法讀取了InputStream對象裏面的內容,而InputStream只能讀取一次,在InputStream讀取之後response的body就空了,後面在獲取結果時得到是null,於是這種方法行不通,除非還是通過http狀態碼來進行判斷,但目前狀態碼條件不滿足,最後還是棄用了FaceResponseErrorHandler,又將restTemplate的返回對象定義爲Object類型。在debug調試過程中意外發現返回的object對象其實是LinkedHashMap類型的,於是採用了一個比較low的方法來解決這個問題,即將res進行了強轉成LinkedHashMap來獲取值,然後對數據進行處理:
/** 強轉數據並處理 */
private IALibraryRes getIALibraryRes(Object res) {
IALibraryRes iaLibraryRes = new IALibraryRes();
if (res != null) {
if (res instanceof LinkedHashMap) {
LinkedHashMap resMap = (LinkedHashMap) res;
if (resMap.containsKey("error_code")) {
for (Object key : resMap.keySet()) {
LOGGER.info(String.valueOf(key) + ": " + String.valueOf(resMap.get(key)));
}
throw new LibraryException(FaceErrorCode.IA_LIBRARY_ERROR, IALibraryServiceImpl.class);
} else {
iaLibraryRes.setLibraryId(String.valueOf(resMap.get("library_id")));
}
} else {
throw new LibraryException(FaceErrorCode.IA_LIBRARY_ERROR, IALibraryServiceImpl.class);
}
} else {
throw new LibraryException(FaceErrorCode.IA_LIBRARY_ERROR, IALibraryServiceImpl.class);
}
return iaLibraryRes;
}
參考網址:
https://blog.csdn.net/achang07/article/details/80549741
https://my.oschina.net/ChenGuop/blog/1581759?tdsourcetag=s_pctim_aiomsg
https://www.cnblogs.com/fzll/p/3400558.html