您的位置:首页 > 理论基础 > 计算机网络

在使用 HttpWebRequest Post数据时候返回 400错误

2016-05-17 11:20 585 查看
笔者有一个项目中用到了上传zip并解压的功能。开始觉得很简单,因为之前曾经做过之类的上传文件的功能,所以并不为意,于是使用copy大法。正如你所料,如果一切很正常的能运行的话就不会有这篇笔记了。

整个系统跑起来以后,在本地开发环境中测试,顺利执行。测试环境中,顺利执行。随着项目的推进,上线。这个功能在前期本身是不重要的,不过当你没有服务器权限的时候,有一个可以随意上传文件的功能还是很不错的,再也不用写邮件,等待,等待,等待,而是可以很快看到修改结果,这样想想还是令人小激动的。so?出来什么问题呢?

在一套模板制作完毕并上传的时候,问题来了,这是jquery中弹出的错误



鬼能看的懂。于是本地调整了接口,指向到本地的api,让api项目进入调试状态,再次上传文件。在费了n多调整步骤之后,抓到了错误:

远程服务器返回错误:(400)错误的请求

这是什么鬼??从来没见过呀!怎么没有错误提示呢??偶买噶!当时笔者的内芯是奔溃的。

立马百度,还真有好多人遇到这个问题,看了n多方案后还是跟我的情况不像。不行,那就分析吧。

笔者的程序中有这个一个函数



///<summary>
///发起httpPost请求,可以上传文件
///</summary>
///<paramname="url">请求的地址</param>
///<paramname="files">文件</param>
///<paramname="input">表单数据</param>
///<paramname="endoding">编码</param>
///<returns></returns>
publicstaticstringPostResponse(stringurl,UpLoadFile[]files,Dictionary<string,string>input,Encodingendoding)
{

stringboundary="----------------------------"+DateTime.Now.Ticks.ToString("x");
HttpWebRequestrequest=(HttpWebRequest)WebRequest.Create(url);
request.ContentType="multipart/form-data;boundary="+boundary;
request.Method="POST";
request.KeepAlive=true;
//request.Credentials=CredentialCache.DefaultCredentials;
request.Expect="";

MemoryStreamstream=newMemoryStream();

byte[]line=Encoding.ASCII.GetBytes("--"+boundary+"\r\n");
byte[]enterER=Encoding.ASCII.GetBytes("\r\n");
////提交文件
if(files!=null)
{
stringfformat="Content-Disposition:form-data;name=\"{0}\";filename=\"{1}\"\r\nContent-Type:{2}\r\n\r\n";
foreach(UpLoadFilefileinfiles)
{

stream.Write(line,0,line.Length);//项目分隔符
strings=string.Format(fformat,file.Name,file.FileName,file.Content_Type);
byte[]data=Encoding.UTF8.GetBytes(s);
stream.Write(data,0,data.Length);
stream.Write(file.Data,0,file.Data.Length);
stream.Write(enterER,0,enterER.Length);//添加\r\n
}
}

//提交文本字段
if(input!=null)
{
stringformat="--"+boundary+"\r\nContent-Disposition:form-data;name=\"{0}\"\r\n\r\n{1}\r\n";//自带项目分隔符
foreach(stringkeyininput.Keys)
{
strings=string.Format(format,key,input[key]);
byte[]data=Encoding.UTF8.GetBytes(s);
stream.Write(data,0,data.Length);
}

}

byte[]foot_data=Encoding.UTF8.GetBytes("--"+boundary+"--\r\n");//项目最后的分隔符字符串需要带上--
stream.Write(foot_data,0,foot_data.Length);

request.ContentLength=stream.Length;
StreamrequestStream=request.GetRequestStream();//写入请求数据
stream.Position=0L;
stream.CopyTo(requestStream);//
stream.Close();

requestStream.Close();

try
{

HttpWebResponseresponse;
try
{
response=(HttpWebResponse)request.GetResponse();

try
{
using(varresponseStream=response.GetResponseStream())
using(varmstream=newMemoryStream())
{
responseStream.CopyTo(mstream);
stringmessage=endoding.GetString(mstream.ToArray());
returnmessage;
}
}
catch(Exceptionex)
{
throwex;
}
}
catch(WebExceptionex)
{
//response=(HttpWebResponse)ex.Response;

//if(response.StatusCode==HttpStatusCode.BadRequest)
//{
//using(Streamdata=response.GetResponseStream())
//{
//using(StreamReaderreader=newStreamReader(data))
//{
//stringtext=reader.ReadToEnd();
//Console.WriteLine(text);
//}
//}
//}

throwex;
}

}
catch(Exceptionex)
{
throwex;
}
}






当然这个函数是正确的,那个错误的已经被修改掉了。

通过调试,传递进来的数据都是正确的那么问题肯定是出在http数据包的拼接上了。

出于习惯,准备把整段代码换掉,实现功能后再分析错误所在,于是百度一下HttpWebRequest上传文件的代码,由于我要实现的是多文件上传,那些单文件上传的例子都被我pass掉,实验了几个网上的例子后觉得还是不行。于是自己提取了数据,使用AdvancedRESTclient(chrome插件)工具模拟post,分析它post时候发送是数据包格式





经过自己对比,发现笔者的程序中在\n\rContent-Type之前有一个分号(;)在上文中代码的第41行处,奔溃在数据包内容部分最后的分隔符结尾不是以--\r\n结尾的在上文代码中54行,于是修改了这两处及对程序做了细微的调整。并再次上传文件得到api返回结果。

至此这给bug总算搞定,不过lz写了这多多字就是为了记录这次修改的胜利么!nonono,不是那样,我是要记录一下这httppost数据包的格式。

笔者随后查阅资料得到:



这个一个请求报文的格式,请求行和请求头部都可以通过HttpWebRequest对象的一些属性来添加,具体有哪些自己百度一下吧,笔者也不是十分清楚,这里就不给出资料了

请求数据需要自己使用字符串拼接,下面给出笔者在这次事件中得到的经验

  -------------------------------------------------------------------------------------------------------

请求数据每一个行需要以括号内的(--分隔符\r\n)进行分割,注意--是必须带的,例如:

"--"+boundary+"\r\n"其中boundary是自定义的分隔符

表单数据最后一项之后的分隔符是以--\r\n结尾的,如下示例:

------WebKitFormBoundarydhy7IYZyMgmp2cLv--
实际上他是"--"+boundary+"--\r\n",可以参考上文中代码54行

 ---------------------------------------------------------------------------------------------

读者如果觉得我讲的比较迷糊可以参考下下面这篇博文进行对比学习http://blog.csdn.net/five3/article/details/7181521
听说Post传输数据有好几种形式哦,后续继续分析,欢迎拍砖

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: