【Java後端】restTemplate異常處理

現在來看原先寫的這篇文章,覺得當時將問題想複雜了。目前最簡單的解決方式大概是:
定義接收對象:

@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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章