首頁 > 軟體

C#記一次http協定multipart/form-data的boundary問題

2022-06-09 22:01:48

1.問題描述

使用post方法呼叫上級聯網廠家介面,返回http狀態碼415,返回資訊Content type ‘application/x-www-form-urlencoded’ not supported

測試上級聯網廠家介面使用的是Postman工具,工具下載地址:https://www.getpostman.com/downloads/

使用application/x-www-form-urlencoded呼叫介面,返回http狀態碼415,如圖:

既然伺服器無法處理請求附帶的媒體格式,那麼改用multipart/form-data試試?

測試後發現可以呼叫成功,如圖:

我們都知道ContentType為application/x-www-form-urlencoded的請求頭、體如何構造,如:

HttpWebRequest request = WebRequest.Create(new Uri(url)) as HttpWebRequest;
request.Method = "POST";
request.Host = Properties.Settings.Default.IP;
request.ContentType = "application/x-www-form-urlencoded; charset=UTF-8";
request.UserAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko";
request.Accept = "*/*";
request.CookieContainer = cc;
request.KeepAlive = true;
string postData = string.Format("action=cx&hphm={0}&hpzl=&jclb=&detlsh=&clpp=&clxh=&rlzl=&pfbz=&jcff=&evl=&staName={1}&detLineId=&syxz=&rqyi={2}&rqer={3}&RQXZ=JCRQ&CXJL=Jiance&cllb=&clgs=&zcrq=&zzl=&clsbdh=&syr=&ccdjrq=&page={4}&rows=10", hphm, staName, rqyi, rqer, page);
byte[] postdatabyte = Encoding.GetEncoding("utf-8").GetBytes(postData);
request.ContentLength = postdatabyte.Length;
using (Stream stream = request.GetRequestStream())
{
	stream.Write(postdatabyte, 0, postdatabyte.Length);
}
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("utf-8")))
{
	string temp = reader.ReadToEnd();
}

但是!multipart/form-data的請求頭與請求體該如何構造呢?像下面這樣?

string url = "http://112.17.158.12:8180/intf/services/query";
HttpWebRequest request = WebRequest.Create(new Uri(url)) as HttpWebRequest;
request.Method = "POST";
request.Host = "112.17.158.12:8180";
request.ContentType = "multipart/form-data; ";
request.UserAgent = "PostmanRuntime/7.17.1";
request.Accept = "*/*";
request.KeepAlive = true;
string postData = @"jkuser=33088102&jkpasswd=33088102&jsondata={""jkid"":""R10"",""requestTime"":""20190919110603"",""body"":[{""inspstationcode"":""33088102""}]}";
byte[] postdatabyte = Encoding.GetEncoding("utf-8").GetBytes(postData);
request.ContentLength = postdatabyte.Length;
using (Stream stream = request.GetRequestStream())
{
	stream.Write(postdatabyte, 0, postdatabyte.Length);
}
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("utf-8")))
{
	string temp = reader.ReadToEnd();
}

顯然不對,捕獲到了"遠端伺服器返回錯誤:(500)內部伺服器錯誤。"異常,那麼我們該怎麼辦呢?

2.解決思路

既然Postman工具使用ContentType為multipart/form-data型別post資料可以成功,那麼我們寫的C#程式應該也可以呀!那怎麼辦呢?。。。。沒錯!!就是抓包!

首先想到的是,用fiddler抓Postman的封包,然後C#程式構造同樣的封包即可。

觀察封包Headers索引標籤,如圖:

發現Content-Type: multipart/form-data;後面跟了一個boundary=----------------------------183584948778966847113836

並且TextView索引標籤如下:

WebForms索引標籤如下:

所以,可以按照Headers和TextView索引標籤內容構造post請求,就可以解決我們的問題了!

3.解決步驟

將ContentType加上boundary=boundary-------------------------xxxxxxxxxxxxxx

並且構造引數,如下:

string url = "http://112.17.158.12:8180/intf/services/query";
string boundary = "--------------------------" + DateTime.Now.Ticks.ToString("x");
string boundary2 = "--" + boundary;
HttpWebRequest request = WebRequest.Create(new Uri(url)) as HttpWebRequest;
request.Method = "POST";
request.Host = "112.17.158.12:8180";
request.ContentType = "multipart/form-data; boundary=" + boundary;
request.UserAgent = "PostmanRuntime/7.17.1";
request.Accept = "*/*";
request.KeepAlive = true;
StringBuilder sb = new StringBuilder();
sb.Append(boundary2 + "rn");
sb.Append(@"Content-Disposition: form-data; name=""jkuser""" + "rnrn");
sb.Append("33088102" + "rn");
sb.Append(boundary2 + "rn");
sb.Append(@"Content-Disposition: form-data; name=""jkpasswd""" + "rnrn");
sb.Append("33088102" + "rn");
sb.Append(boundary2 + "rn");
sb.Append(@"Content-Disposition: form-data; name=""jsondata""" + "rnrn");
sb.Append(@"{""jkid"":""R10"",""requestTime"":""20190919110603"",""body"":[{""inspstationcode"":""33088102""}]}" + "rn");
sb.Append(boundary2 + "--" + "rn");
string postData = sb.ToString();
byte[] postdatabyte = Encoding.GetEncoding("utf-8").GetBytes(postData);
request.ContentLength = postdatabyte.Length;
using (Stream stream = request.GetRequestStream())
{
    stream.Write(postdatabyte, 0, postdatabyte.Length);
}
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("utf-8")))
{
    string temp = reader.ReadToEnd();
}

值得注意的是,“boundary-------------------------xxxxxxxxxxxxxx”

這麼長一串東西,只是作為分隔符出現的,不必太在意它是什麼東西,我將它理解為分割文字引數的這麼一個東西,並且通過仔細觀察發現可以發現header中contenttype的橫線數量比引數中橫線數量少兩個且必須少兩個?

以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。 


IT145.com E-mail:sddin#qq.com