本文閱讀前了解知識:什么時候需要使用UrlEncode和UrlDecode函式
作者使用谷歌瀏覽器,通過按下F12對第三方網站http協議的介面抓包進行分析操作,
場景
運維小哥哥偶爾使用某某外包公司的網站系統,做設備錄入作業,流程簡單:

- 錄入設備基本資訊,有7、8個欄位需要輸入,然后點擊保存按鈕;
- 基本資訊保存成功,進入設備型別選擇操作,然后點擊生成設備標識按鈕;
- 設備標識生成成功,錄入設備關聯的模塊資訊,簡單設備只需要錄入2條模塊,復雜的設備有6條模塊,每個模塊有3、4個欄位需要輸入,最后點擊保存,
一條設備錄入成功,單身多年的手速可能也花不了幾分鐘,其實這也沒啥,
突然領導說有1000個設備需要搞?運維小哥哥哭了??,這時就該開發人員上場了:
- 運維準備一個Excel模板,輸入需要錄入的1000個設備基本資訊、設備型別資訊,這個作業量不大,就半天吧,最多一天作業量;
- 開發做個C/S客戶端小工具,程式中按業務要求配置模塊錄入規則;
- 程式執行程序中錄入一個設備就把生成的設備標識與設備關聯;
- 全部錄入完成,提供一個Excel匯出,可將設備基本資訊、生成的設備標識全部關聯匯出,作業完成,
經過幾天的開發作業,開發哥哥將精心打磨的小工具交給運維小哥,運維小哥哥使用后投來了贊許的目光...
問題
前面鋪墊的話有點啰嗦了,開發這個小工具時,開發小哥遇到一個問題:

這是某個介面的資訊,Content-Type 是 application/x-www-form-urlencoded,下面引數使用的Form Data,即引數使用了UrlEncode,比如未編碼前的一個引數:
"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());
}
文末分享
- 后臺回復數字【00】:獲取DotNet、Java、C++、前端等技術資料
- 添加微信群:添加號主微信號【dotnet9】,備注【入群】
- 添加QQ群:群號【771992300】,備注【Dotnet9】
時間如流水,只能流去不流回,
- 公眾號:Dotnet9
- 號主微信號:dotnet9
- 作者及編輯:沙漠之盡頭的狼
- 原文鏈接:點擊閱讀
- 日期:2021-01-09
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/246997.html
標籤:C#
下一篇:c#委托和事件

