一不小心又踩feign的坑

java金融發表於2021-12-06

引言

前陣子不是剛剛使用feign呼叫了第三方的介面嗎《feign的一個註解居然隱藏這麼多知識!》覺得feign這玩意還挺好用,程式碼寫起來比較簡單,
不過也被讀者噴啦,引入一個httpClien就能夠解決的問題,非要搞得這麼複雜。其實本來專案裡面就是採用feign來進行和其他業務進行互動的,所以沒有必要再去搞一個HttpUtils。最近又收到一個需求,需要繼續接入第三方的一個影片校驗影片。為啥要去接入影片校驗,主要是比如使用者傳入一個影片,我們需要對這個影片進行校驗,看看這個影片是否合規,是否涉黃、涉政等。如果這些影片都需要人工一個個去稽核的話,這樣比較耗費人力,所以需要接入阿里雲的影片校驗功能,透過這個來幫我們解決這個影片是否合規的問題。看了下文件對接起來還是比較容易的引數也就幾個一個是影片的url,還有一個是影片需要校驗的情況有哪些。

踩坑

背景介紹完了我們就直接接入就可以啦,三下五除二就接完了,自測了幾個小影片看下來都是符合正常流程,然後就提測了。
測試測了十幾個case也沒發現啥問題,然後就跟著下一個釋出版本正常釋出生產啦,生產也看啦幾個影片沒啥問題。然後這個功能就算正式
互動完成啦。不過過了幾天就又被運營找上來了,說好多突然積累啦好多影片稽核都是失敗的,我心想你肯定是不會用,上線的時候都是好好的,肯定是你操作姿勢不對。嘀咕歸滴咕問題還是需要去解決的。
首先開啟下日誌發現好多報錯都是返回同一個錯誤碼,但是也有呼叫成功的。既然是第三方返回的報錯那肯定是第三方的bug了,如果是我寫的bug那肯定都會是校驗失敗的就不會存在部分成功和部分失敗啦,所以我隨手挑了一個報錯的case,把請求引數,以及請求返回結果扔給第三方讓他們幫忙查下是啥問題。讓人家排查問題最起碼的東西還是需要提供的,比如呼叫時間、請求引數、請求介面等這資訊。有了這些資訊人家才能更方便快捷的幫你定位問題。但是在公司裡面往往業務方找你排查問題就是直接@你,呼叫你的介面報錯了,趕緊解決下。不說哪個環境?也不說哪個介面?也不發下請求引數。反正啥都沒有,就是你的問題,趕緊給我解決就行。但是這樣往往都是自己漏傳了這個引數,或者是自己環境不對。找人幫你定位問題,問題三要素至少要說清楚吧?至少需要先自己排查下是否是你的問題吧?這應該是作為程式設計師最基本的素養吧!扯遠啦回到正題。畢竟花錢了的,作為第三方排查生產問題響應速度還是可以的,立馬就定位到問題了。原來是我提交過去的影片連結打不開,導致無法被校驗,所以返回校驗失敗。但是我根據我這邊記錄的日誌這個影片連結是可以開啟的。我馬上讓他們把他們接受到的引數發給我下,然後和我這邊記錄日誌的連結對比下:
在這裡插入圖片描述

我們可以發現不同點就是在最後幾個字母,知道的朋友肯定一眼就能看出問題所在了,第三方接受到的URL是被decode了,然後我們自己這邊的URL能開啟的話就是這個連結有些特殊字元需要被encode之後才能被開啟,如果直接decode之後就不能夠開啟了。然後找第三方的人確認是否他們有對我們的引數進行decode,最終得到的結論是沒有。那難道是我們程式碼的問題,仔細檢查了下程式碼發現了這麼一行可能有影響的程式碼

 @PostMapping(value = "xxxx", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    Response submit(@SpringQueryMap VideoValidationSubmitReq req);

這個produces是按照提供的文件接入的看下來應該沒啥問題。
在這裡插入圖片描述
然後透過POSTMAN除錯一把也沒有復現出問題,那問題肯定是出在feign呼叫的過程中啦。原始碼之下無秘密,經過上次踩坑事件,《feign的一個註解居然隱藏這麼多知識!》閱讀過原始碼,這次閱讀它的原始碼就有點輕車熟路了,最終很快就定位到問題了。最終定位到問題的關鍵程式碼是這一行,

UriUtils.encode

在這裡插入圖片描述
我們可以進入這個方法首先看看這個方法的註釋我們就明白其中的原因所在了:
在這裡插入圖片描述
如果需要進行encode的引數已經是被encode了就不會被繼續被encode了,直接跳過這個字元。很明顯上述我們的引數已經是有部分已經被encode了,然後在透過feign傳過去之後只有沒有被encode 的引數才會繼續encode,這樣就會導致第三方服務端那邊接受到這邊的引數再經過decode所以我傳過去的URL引數就全部被解密了。全部解密後然後就導致url解析後失敗了,不能夠被正常開啟了。找到原因了我們解決問題就比較簡單了,既然feign使用的encode不能滿足我們的要求,我們就不使用它的提供的方法,本著快速解決bug的原則然後把produces 指定為application/json;charset=UTF-8",然後把引數透過手動呼叫URLEncoder.encode(xxx,"utf-8")`把引數傳給第三方。
這個方法如果已經被encode的字串也會繼續第二次encode並不會和UriUtils.encode一樣遇到已經被encode的字元就直接不encode了。快速修復完這個bug然後讓測試幫忙測了一把沒啥問題,趕緊釋出到生產去,不然運營人員一直崔個不停。程式碼被髮布上去之後,把校驗失敗的影片改下狀態,然後手動觸發下job讓它重新跑一下,觀察了一會全部校驗透過。這個bug`總算修復了,雖然解決的不是很完美,但是先把問題修了再說,後續再去研究下比較優雅的解決方法還得趕緊跟領導去解釋原因去?不然年終獎不知道還有麼有?

結束

  • 由於自己才疏學淺,難免會有紕漏,假如你發現了錯誤的地方,還望留言給我指出來,我會對其加以修正。
  • 如果你覺得文章還不錯,你的轉發、分享、讚賞、點贊、留言就是對我最大的鼓勵。
  • 感謝您的閱讀,十分歡迎並感謝您的關注。