本文閱讀前瞭解知識:何時須要使用UrlEncode和UrlDecode函數html
做者使用谷歌瀏覽器,經過按下F12對第三方網站http協議的接口抓包進行分析操做。前端
運維小哥哥偶爾使用某某外包公司的網站系統,作設備錄入工做,流程簡單:json
一條設備錄入成功,單身多年的手速可能也花不了幾分鐘,其實這也沒啥。api
忽然領導說有1000個設備須要搞?運維小哥哥哭了😂,這時就該開發人員上場了:瀏覽器
通過幾天的開發工做,開發哥哥將精心打磨的小工具交給運維小哥,運維小哥哥使用後投來了讚許的目光...服務器
前面鋪墊的話有點囉嗦了,開發這個小工具時,開發小哥遇到一個問題:微信
這是某個接口的信息,Content-Type
是 application/x-www-form-urlencoded
,下面參數使用的Form Data
,即參數使用了UrlEncode
,好比未編碼前的一個參數:app
"Content":"{"AP_Name":"HK_7889","IP":"192.168.0.1"}"
編碼後(可使用這個在線URL編碼解碼工具驗證):運維
"Content":"%7B%22AP_Name%22%3A%22HK_7889%22%2C%22IP%22%3A%2292.168.0.1%22%7D"
使用Postman
測試時,未對參數使用UrlEncode
,接口測試成功,開發這個小工具時,有3個接口都是相似的,未進行UrlEncode
操做:函數
var client = new RestClient("http://admin.lqclass.com/api/device"); client.Timeout = -1; var request = new RestRequest(Method.POST); request.AddHeader("Content-Type", "application/x-www-form-urlencoded"); request.AddParameter("Content", "{\"AP_Name\":\"HK_7889\",\"IP\":\"92.168.0.1\"}"); IRestResponse response = client.Execute(request); Console.WriteLine(response.Content);
但遇到稍微複雜一點的接口,好比截圖中的參數爲:
"Content":"{"AP_Name":"HK_7889","IP":"192.168.0.1","Module":[{"M_Name":"cameri0","Desc":"cameri0","AP_PUID":"54632325461320320"},{"M_Name":"cameri1","Desc":"cameri1","AP_PUID":"54636325461320320"},{"M_Name":"cameri2","Desc":"cameri2","AP_PUID":"54632325421320320"}]}"
Content
值格式化看得清楚一點,Module
是設備關聯的模塊信息:
{ "AP_Name": "HK_7889", "IP": "192.168.0.1", "Module": [ { "M_Name": "cameri0", "Desc": "cameri0", "AP_PUID": "54632325461320320" }, { "M_Name": "cameri1", "Desc": "cameri1", "AP_PUID": "54636325461320320" }, { "M_Name": "cameri2", "Desc": "cameri2", "AP_PUID": "54632325421320320" } ] }
實際UrlEncode
後的參數爲:
"Content":"%7B%22AP_Name%22%3A%22HK_7889%22%2C%22IP%22%3A%22192.168.0.1%22%2C%22Module%22%3A%22%255B%257B%2522M_Name%2522%253A%2522cameri0%2522%252C%2522Desc%2522%253A%2522cameri0%2522%252C%2522AP_PUID%2522%253A%252254632325461320320%2522%257D%252C%257B%2522M_Name%2522%253A%2522cameri1%2522%252C%2522Desc%2522%253A%2522cameri1%2522%252C%2522AP_PUID%2522%253A%252254636325461320320%2522%257D%252C%257B%2522M_Name%2522%253A%2522cameri2%2522%252C%2522Desc%2522%253A%2522cameri2%2522%252C%2522AP_PUID%2522%253A%252254632325421320320%2522%257D%255D%22%7D"
原本通常接口,如上面成功執行的C#代碼那般直接未UrlEncode
調用是沒問題的。
但這個接口調用,服務器返回錯誤信息:「xxx解析失敗」,調用代碼以下:
var client = new RestClient("http://admin.lqclass.com/api/device"); client.Timeout = -1; var request = new RestRequest(Method.POST); request.AddHeader("Content-Type", "application/x-www-form-urlencoded"); request.AddParameter("Content", "{\"AP_Name\":\"HK_7889\",\"IP\":\"192.168.0.1\",\"Module\":[{\"M_Name\":\"cameri0\",\"Desc\":\"cameri0\",\"AP_PUID\":\"54632325461320320\"},{\"M_Name\":\"cameri1\",\"Desc\":\"cameri1\",\"AP_PUID\":\"54636325461320320\"},{\"M_Name\":\"cameri2\",\"Desc\":\"cameri2\",\"AP_PUID\":\"54632325421320320\"}]}"); IRestResponse response = client.Execute(request); Console.WriteLine(response.Content);
兩處調用代碼哪裏不一樣?只是Content值不同,最後懷疑是否是須要手動進行UrlEncode
?又不是url參數,爲啥須要編碼呢?無論啦,先編碼了再說。
參數編碼後,調用:
var client = new RestClient("http://admin.lqclass.com/api/device"); client.Timeout = -1; var request = new RestRequest(Method.POST); request.AddHeader("Content-Type", "application/x-www-form-urlencoded"); request.AddParameter("Content", "%7B%22AP_Name%22%3A%22HK_7889%22%2C%22IP%22%3A%22192.168.0.1%22%2C%22Module%22%3A%22%255B%257B%2522M_Name%2522%253A%2522cameri0%2522%252C%2522Desc%2522%253A%2522cameri0%2522%252C%2522AP_PUID%2522%253A%252254632325461320320%2522%257D%252C%257B%2522M_Name%2522%253A%2522cameri1%2522%252C%2522Desc%2522%253A%2522cameri1%2522%252C%2522AP_PUID%2522%253A%252254636325461320320%2522%257D%252C%257B%2522M_Name%2522%253A%2522cameri2%2522%252C%2522Desc%2522%253A%2522cameri2%2522%252C%2522AP_PUID%2522%253A%252254632325421320320%2522%257D%255D%22%7D"); IRestResponse response = client.Execute(request); Console.WriteLine(response.Content);
哈哈,成功了,這裏簡單猜想下:別人的服務對接收的參數可能作了UrlDecode
操做。
其實中間還作了一個參數的UrlEncode
操做,即下面的Module
參數值:
"Content":{"AP_Name":"HK_7889","IP":"192.168.0.1","Module":[{"M_Name":"cameri0","Desc":"cameri0","AP_PUID":"54632325461320320"},{"M_Name":"cameri1","Desc":"cameri1","AP_PUID":"54636325461320320"},{"M_Name":"cameri2","Desc":"cameri2","AP_PUID":"54632325421320320"}]}
第一次UrlEncode
,即先對Module
的值進行UrlEncode
:
"Content":{"AP_Name":"HK_7889","IP":"192.168.0.1","Module":%5B%7B%22M_Name%22%3A%22cameri0%22%2C%22Desc%22%3A%22cameri0%22%2C%22AP_PUID%22%3A%2254632325461320320%22%7D%2C%7B%22M_Name%22%3A%22cameri1%22%2C%22Desc%22%3A%22cameri1%22%2C%22AP_PUID%22%3A%2254636325461320320%22%7D%2C%7B%22M_Name%22%3A%22cameri2%22%2C%22Desc%22%3A%22cameri2%22%2C%22AP_PUID%22%3A%2254632325421320320%22%7D%5D}
第二次UrlEncode
便是上面成功的參數方式了,對整個Content
的值進行UrlEncode
,看上面成功的參數,不重複貼了。
抓別人數據包時,不要憑印象、已有知識斷定該怎麼怎麼作,好比前面的參數,不使用UrlEncode
時,調用成功了,其餘包我是否也沿用相同的方式使用就正確呢?搞不定時,多嘗試猜想的方法。
總結:「管他的,幹就是了」。
本文使用的UrlEncode
C# 代碼:
public static string UrlEncode(string str) { StringBuilder sb = new StringBuilder(); byte[] byStr = System.Text.Encoding.UTF8.GetBytes(str); //默認是System.Text.Encoding.Default.GetBytes(str) for (int i = 0; i < byStr.Length; i++) { sb.Append(@"%" + Convert.ToString(byStr[i], 16)); } return (sb.ToString()); }
時間如流水,只能流去不流回。
- 公衆號:Dotnet9
- 號主微信號:dotnet9
- 做者及編輯:沙漠之盡頭的狼
- 原文連接:點擊閱讀
- 日期:2021-01-09