feign 調用第三方服務中部分特殊符號未轉義

開發過程中,發現+(加號)這個符號沒有轉義,導致再調用服務的時候把加號轉義成空格了。導致後臺獲取到的數據會不正確。

1. 問題發現過程

feign 解析參數的時候,使用的標準是 RFC 3986,這個標準的加號是不需要被轉義的。其具體的實現是 feign.template.UriUtils#encodeReserved(String value, String reserved, Charset charset)

2. 解決辦法

feign 調用過程

1. feign核心先將(定義好的feign接口)接口中的參數解析出來
2. 對接實際參數和接口參數(入參調用的參數)
3. 對入參的參數進行編碼(UriUtils#encodeReserved)(問題出在這裏)
4. 調用註冊的 RequestInterceptor(自定義)
5. Encoder 實現類,這裏是body裏面的內容纔會有調用(自定義)
6. 具體的http網絡請求邏輯

依據上面的過程,我們可以實現一個 RequestInterceptor 攔截器,在這裏對參數再次進行轉義即可。

public void apply(RequestTemplate template) {

    Map<String, Collection<String>> _queries = template.queries();
    if (!_queries.isEmpty()) {
        //由於在最新的  RFC 3986  規範,+號是不需要編碼的,因此spring 實現的是這個規範,這裏就需要參數中進行編碼先,兼容舊規範。
        Map<String, Collection<String>> encodeQueries = new HashMap<String, Collection<String>>(_queries.size());

        Iterator<String> iterator = _queries.keySet().iterator();
        Collection<String> encodeValues = null;
        while (iterator.hasNext()) {
            encodeValues = new ArrayList<>();

            String key = iterator.next();
            Collection<String> values = _queries.get(key);

            for (String _str : values) {
                _str = _str.replaceAll("\\+", "%2B");
                encodeValues.add(_str);
            }
            encodeQueries.put(key, encodeValues);
        }
        template.queries(null);
        template.queries(encodeQueries);
    }
}

上面是代碼片段,詳細請查看 FeignRequestInterceptor.java

3. 疑問

3.1 是否可以使用 HTTPClient 的實現就可以解決問題?

也不行,如果不做上面的實現,直接改用HTTPClient實現的話,也只是在發送的過程中起到作用,還是需要在前進行處理。

4. 參考文獻

https://spring.hhui.top/spring-blog/2019/03/27/190327-Spring-RestTemplate之urlencode參數解析異常全程分析/

https://www.w3school.com.cn/tags/html_ref_urlencode.html

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