一不小心又踩了個feign的坑!
作者丨碼農(nóng)二胖
來源丨java金融
引言
前陣子不是剛剛使用feign調(diào)用了第三方的接口嗎,覺得feign這玩意還挺好用,代碼寫起來比較簡單, 不過也被讀者噴啦,引入一個httpClien就能夠解決的問題,非要搞得這么復(fù)雜。其實本來項目里面就是采用feign來進行和其他業(yè)務(wù)進行交互的,所以沒有必要再去搞一個HttpUtils。最近又收到一個需求,需要繼續(xù)接入第三方的一個視頻校驗視頻。為啥要去接入視頻校驗,主要是比如用戶傳入一個視頻,我們需要對這個視頻進行校驗,看看這個視頻是否合規(guī),是否涉黃、涉政等。如果這些視頻都需要人工一個個去審核的話,這樣比較耗費人力,所以需要接入阿里云的視頻校驗功能,通過這個來幫我們解決這個視頻是否合規(guī)的問題??戳讼挛臋n對接起來還是比較容易的參數(shù)也就幾個一個是視頻的url,還有一個是視頻需要校驗的情況有哪些。
踩坑
背景介紹完了我們就直接接入就可以啦,三下五除二就接完了,自測了幾個小視頻看下來都是符合正常流程,然后就提測了。測試測了十幾個case也沒發(fā)現(xiàn)啥問題,然后就跟著下一個發(fā)布版本正常發(fā)布生產(chǎn)啦,生產(chǎn)也看啦幾個視頻沒啥問題。然后這個功能就算正式 交互完成啦。不過過了幾天就又被運營找上來了,說好多突然積累啦好多視頻審核都是失敗的,我心想你肯定是不會用,上線的時候都是好好的,肯定是你操作姿勢不對。嘀咕歸滴咕問題還是需要去解決的。首先打開下日志發(fā)現(xiàn)好多報錯都是返回同一個錯誤碼,但是也有調(diào)用成功的。既然是第三方返回的報錯那肯定是第三方的bug了,如果是我寫的bug那肯定都會是校驗失敗的就不會存在部分成功和部分失敗啦。所以我隨手挑了一個報錯的case,把請求參數(shù),以及請求返回結(jié)果扔給第三方讓他們幫忙查下是啥問題。讓人家排查問題最起碼的東西還是需要提供的,比如調(diào)用時間、請求參數(shù)、請求接口等這信息。有了這些信息人家才能更方便快捷的幫你定位問題。但是在公司里面往往業(yè)務(wù)方找你排查問題就是直接@你,調(diào)用你的接口報錯了,趕緊解決下。不說哪個環(huán)境?也不說哪個接口?也不發(fā)下請求參數(shù)。反正啥都沒有,就是你的問題,趕緊給我解決就行。但是這樣往往都是自己漏傳了這個參數(shù),或者是自己環(huán)境不對。找人幫你定位問題,問題三要素至少要說清楚吧?至少需要先自己排查下是否是你的問題吧?這應(yīng)該是作為程序員最基本的素養(yǎng)吧!扯遠啦回到正題。畢竟花錢了的,作為第三方排查生產(chǎn)問題響應(yīng)速度還是可以的,立馬就定位到問題了。原來是我提交過去的視頻鏈接打不開,導(dǎo)致無法被校驗,所以返回校驗失敗。但是我根據(jù)我這邊記錄的日志這個視頻鏈接是可以打開的。我馬上讓他們把他們接受到的參數(shù)發(fā)給我下,然后和我這邊記錄日志的鏈接對比下:
我們可以發(fā)現(xiàn)不同點就是在最后幾個字母,知道的朋友肯定一眼就能看出問題所在了,第三方接受到的URL是被decode了,然后我們自己這邊的URL能打開的話就是這個鏈接有些特殊字符需要被encode之后才能被打開,如果直接decode之后就不能夠打開了。然后找第三方的人確認是否他們有對我們的參數(shù)進行decode,最終得到的結(jié)論是沒有。那難道是我們代碼的問題,仔細檢查了下代碼發(fā)現(xiàn)了這么一行可能有影響的代碼
@PostMapping(value = "xxxx", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
Response submit(@SpringQueryMap VideoValidationSubmitReq req);
這個produces是按照提供的文檔接入的看下來應(yīng)該沒啥問題。
然后通過POSTMAN調(diào)試一把也沒有復(fù)現(xiàn)出問題,那問題肯定是出在feign調(diào)用的過程中啦。源碼之下無秘密,經(jīng)過上次踩坑事件,《feign的一個注解居然隱藏這么多知識!》閱讀過源碼,這次閱讀它的源碼就有點輕車熟路了,最終很快就定位到問題了。最終定位到問題的關(guān)鍵代碼是這一行,
UriUtils.encode
我們可以進入這個方法首先看看這個方法的注釋我們就明白其中的原因所在了:
如果需要進行encode的參數(shù)已經(jīng)是被encode了就不會被繼續(xù)被encode了,直接跳過這個字符。很明顯上述我們的參數(shù)已經(jīng)是有部分已經(jīng)被encode了,然后在通過feign傳過去之后只有沒有被encode 的參數(shù)才會繼續(xù)encode,這樣就會導(dǎo)致第三方服務(wù)端那邊接受到這邊的參數(shù)再經(jīng)過decode所以我傳過去的URL參數(shù)就全部被解密了。全部解密后然后就導(dǎo)致url解析后失敗了,不能夠被正常打開了。找到原因了我們解決問題就比較簡單了,既然feign使用的encode不能滿足我們的要求,我們就不使用它的提供的方法,本著快速解決bug的原則然后把produces 指定為application/json;charset=UTF-8",然后把參數(shù)通過手動調(diào)用URLEncoder.encode(xxx,"utf-8")把參數(shù)傳給第三方。這個方法如果已經(jīng)被encode的字符串也會繼續(xù)第二次encode并不會和UriUtils.encode一樣遇到已經(jīng)被encode的字符就直接不encode了。快速修復(fù)完這個bug然后讓測試幫忙測了一把沒啥問題,趕緊發(fā)布到生產(chǎn)去,不然運營人員一直催個不停。代碼被發(fā)布上去之后,把校驗失敗的視頻改下狀態(tài),然后手動觸發(fā)下job讓它重新跑一下,觀察了一會全部校驗通過。幸好我當(dāng)時多了個心眼留了個后門可以通過job重新拉取校驗失敗的視頻。這個bug總算修復(fù)了,雖然解決的不是很完美,但是先把問題修了再說,后續(xù)再去研究下比較優(yōu)雅的解決方法,還得趕緊跟領(lǐng)導(dǎo)去解釋原因去?不然年終獎不知道還有么有?
結(jié)束
-
由于自己才疏學(xué)淺,難免會有紕漏,假如你發(fā)現(xiàn)了錯誤的地方,還望留言給我指出來,我會對其加以修正。 -
如果你覺得文章還不錯,你的轉(zhuǎn)發(fā)、分享、贊賞、點贊、留言就是對我最大的鼓勵。 -
感謝您的閱讀,十分歡迎并感謝您的關(guān)注。
-End-
最近有一些小伙伴,讓我?guī)兔φ乙恍?nbsp;面試題 資料,于是我翻遍了收藏的 5T 資料后,匯總整理出來,可以說是程序員面試必備!所有資料都整理到網(wǎng)盤了,歡迎下載!

面試題】即可獲取
