場景
有時我們開發了一個api接口,自己調得好好的,接口文檔也寫好了,但別人調用時就是有問題,而當我們調試時,發現請求根本沒進來或進來了卻取不到調用參數,該怎么告知對方調用姿勢哪不對呢?
解決方法
對於編碼新手,一般會和對方撕扯一會,然后甚至去review對方的代碼,這樣也許能解決問題,但自己畢竟不熟悉別人系統的實現,耗費時間較長。
另外api調用端可能因為封裝方式不同或者加過一些攔截器,導致你看調用端的代碼根本看不到什么問題,或者因為調用參數有一些不易分辨或不可見的特殊字符,讓你無法察覺到這里有問題。
其實這種問題,我們從網絡層出發,對比自己正確調用時的數據包與對方錯誤調用時的數據包內容,以此來診斷問題所在更加高效,畢竟任何封裝或攔截器的處理,最終都會反饋在底層的交互數據上。
這里,我使用springmvc開發一個簡單的接口,如下:
@RestController
public class TestController {
@RequestMapping(value = "/test",produces = MimeTypeUtils.TEXT_PLAIN_VALUE)
@ResponseBody
public String test(@RequestParam(name = "name") String name){
return name;
}
}
復制代碼
這個接口就是直接將name參數的值返回了,然后我使用curl模擬正確與錯誤的調用方式,如下:
正確調用方式
$ curl http://localhost:8081/test --data-urlencode 'name=a+b'
a+b
錯誤調用方式
$ curl http://localhost:8081/test --data 'name=a+b'
a b
復制代碼
假設調用方的代碼實現的邏輯類似上面錯誤的調用方式,傳遞name參數為a+b,得到的卻是a b,接下來我們來定位看看,錯誤的調用方法問題在哪?
使用socat命令
在抓包工具無法使用的情況下,可以嘗試socat命令,使用socat命令來中轉請求,調用端將請求先發給socat,socat再把請求轉給服務端,如下:
使用socat中轉請求
$ socat -v TCP4-LISTEN:8080,bind=0.0.0.0,reuseaddr,fork TCP4:localhost:8081
調用端訪問socat監聽的8080端口
正確調用方式
$ curl http://localhost:8080/test --data-urlencode 'name=a+b'
a+b
錯誤調用方式
$ curl http://localhost:8080/test --data 'name=a+b'
a b
復制代碼
再去看socat,會發現如下結果
其中socat添加-v參數后,會自動將中轉的數據流以明文顯示出來,其中類似> 2020/10/11 13:05:03.536294 length=162 from=0 to=161之后的部分,就是請求數據,而類似< 2020/10/11 13:05:03.740585 length=116 from=0 to=115之后的部分,就是響應數據,同樣的,你可以將兩次請求數據復制到文本對比工具中去發現差異。
有時這種調用差異是特殊字符導致的,比如空白字符、零寬字符,上面的方式可能看不出差異,這時你可以將-v參數替換為-x參數,來對比數據的十六進制,同樣的wireshark也可以查看數據包的十六進制,相信你摸索一下也可以找到。