C#记一次http协议multipart/form-data的boundary问题
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 + "\r\n"); sb.Append(@"Content-Disposition: form-data; name=""jkuser""" + "\r\n\r\n"); sb.Append("33088102" + "\r\n"); sb.Append(boundary2 + "\r\n"); sb.Append(@"Content-Disposition: form-data; name=""jkpasswd""" + "\r\n\r\n"); sb.Append("33088102" + "\r\n"); sb.Append(boundary2 + "\r\n"); sb.Append(@"Content-Disposition: form-data; name=""jsondata""" + "\r\n\r\n"); sb.Append(@"{""jkid"":""R10"",""requestTime"":""20190919110603"",""body"":[{""inspstationcode"":""33088102""}]}" + "\r\n"); sb.Append(boundary2 + "--" + "\r\n"); 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的横线数量比参数中横线数量少两个且必须少两个?
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
相关文章
Stream.Write 与 StreamWriter.Write 的不同
Stream.Write 与 StreamWriter.Write 是我们在向流中写数据时,最常用的方法。下面就详细讲解这两个方法。2013-04-04Unity的IPostprocessBuildWithReport实用案例深入解析
这篇文章主要为大家介绍了Unity的IPostprocessBuildWithReport实用案例深入解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪2023-05-05C#判断字符串中是否包含指定字符串及contains与indexof方法效率问题
这篇文章主要介绍了C#判断字符串中是否包含指定字符串及contains与indexof方法效率问题 ,文中给大家列举通过两种方法来判断,需要的朋友可以参考下2018-10-10C#控制台程序实现开启、关闭SQLServer服务的代码分享
这篇文章主要介绍了C#控制台程序实现开启、关闭SQLServer服务的代码分享,需要的朋友可以参考下2014-05-05
最新评论