在使用 HttpWebRequest Post数据时候返回 400错误
笔者有一个项目中用到了上传zip并解压的功能。开始觉得很简单,因为之前曾经做过之类的上传文件的功能,所以并不为意,于是使用copy大法。正如你所料,如果一切很正常的能运行的话就不会有这篇笔记了。
整个系统跑起来以后,在本地开发环境中测试,顺利执行。测试环境中,顺利执行。随着项目的推进,上线。这个功能在前期本身是不重要的,不过当你没有服务器权限的时候,有一个可以随意上传文件的功能还是很不错的,再也不用写邮件,等待,等待,等待,而是可以很快看到修改结果,这样想想还是令人小激动的。 so? 出来什么问题呢?
在一套模板制作完毕并上传的时候,问题来了,这是jquery 中弹出的错误

鬼能看的懂。于是本地调整了接口,指向到本地的api,让api项目进入调试状态,再次上传文件。在费了n多调整步骤之后,抓到了错误:
远程服务器返回错误:(400)错误的请求
这是什么鬼?? 从来没见过呀!怎么没有错误提示呢??偶买噶!当时笔者的内芯是奔溃的。
立马百度,还真有好多人遇到这个问题,看了n多方案后还是跟我的情况不像。不行,那就分析吧。
笔者的程序中有这个一个函数
/// <summary>
/// 发起httpPost 请求,可以上传文件
/// </summary>
/// <param name="url">请求的地址</param>
/// <param name="files">文件</param>
/// <param name="input">表单数据</param>
/// <param name="endoding">编码</param>
/// <returns></returns>
public static string PostResponse(string url, UpLoadFile[] files, Dictionary<string, string> input, Encoding endoding)
{ string boundary = "----------------------------" + DateTime.Now.Ticks.ToString("x");
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.ContentType = "multipart/form-data; boundary=" + boundary;
request.Method = "POST";
request.KeepAlive = true;
//request.Credentials = CredentialCache.DefaultCredentials;
request.Expect = ""; MemoryStream stream = new MemoryStream(); byte[] line = Encoding.ASCII.GetBytes("--" + boundary + "\r\n");
byte[] enterER = Encoding.ASCII.GetBytes("\r\n");
////提交文件
if (files != null)
{
string fformat = "Content-Disposition:form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type:{2}\r\n\r\n";
foreach (UpLoadFile file in files)
{ stream.Write(line, , line.Length); //项目分隔符
string s = string.Format(fformat, file.Name, file.FileName, file.Content_Type);
byte[] data = Encoding.UTF8.GetBytes(s);
stream.Write(data, , data.Length);
stream.Write(file.Data, , file.Data.Length);
stream.Write(enterER, , enterER.Length); //添加\r\n
}
} //提交文本字段
if (input != null)
{
string format = "--" + boundary + "\r\nContent-Disposition:form-data;name=\"{0}\"\r\n\r\n{1}\r\n"; //自带项目分隔符
foreach (string key in input.Keys)
{
string s = string.Format(format, key, input[key]);
byte[] data = Encoding.UTF8.GetBytes(s);
stream.Write(data, , data.Length);
} } byte[] foot_data = Encoding.UTF8.GetBytes("--" + boundary + "--\r\n"); //项目最后的分隔符字符串需要带上--
stream.Write(foot_data, , foot_data.Length); request.ContentLength = stream.Length;
Stream requestStream = request.GetRequestStream(); //写入请求数据
stream.Position = 0L;
stream.CopyTo(requestStream); //
stream.Close(); requestStream.Close(); try
{ HttpWebResponse response;
try
{
response = (HttpWebResponse)request.GetResponse(); try
{
using (var responseStream = response.GetResponseStream())
using (var mstream = new MemoryStream())
{
responseStream.CopyTo(mstream);
string message = endoding.GetString(mstream.ToArray());
return message;
}
}
catch (Exception ex)
{
throw ex;
}
}
catch (WebException ex)
{
//response = (HttpWebResponse)ex.Response; //if (response.StatusCode == HttpStatusCode.BadRequest)
//{
// using (Stream data = response.GetResponseStream())
// {
// using (StreamReader reader = new StreamReader(data))
// {
// string text = reader.ReadToEnd();
// Console.WriteLine(text);
// }
// }
//} throw ex;
} }
catch (Exception ex)
{
throw ex;
}
}
当然这个函数是正确的,那个错误的已经被修改掉了。
通过调试,传递进来的数据都是正确的那么问题肯定是出在http数据包的拼接上了。
出于习惯,准备把整段代码换掉,实现功能后再分析错误所在,于是百度一下 HttpWebRequest 上传文件的代码,由于我要实现的是多文件上传,那些单文件上传的例子都被我pass掉,实验了几个网上的例子后觉得还是不行。于是自己提取了数据,使用Advanced REST client(chrome插件) 工具模拟post,分析它post时候发送是数据包格式


经过自己对比,发现笔者的程序中在\n\rContent-Type之前有一个分号(;)在上文中代码的第41行处,奔溃在数据包内容部分最后的分隔符 结尾不是以 --\r\n结尾的 在上文代码中54行,于是修改了这两处及对程序做了细微的调整。并再次上传文件得到api返回结果。
至此这给bug总算搞定,不过lz写了这多多字就是为了记录这次修改的胜利么!no no no,不是那样,我是要记录一下这http post数据包的格式。
笔者随后查阅资料得到:

这个一个请求报文的格式,请求行和请求头部都可以通过 HttpWebRequest 对象的一些属性来添加,具体有哪些自己百度一下吧,笔者也不是十分清楚,这里就不给出资料了
请求数据需要自己 使用字符串拼接,下面给出笔者在这次事件中得到的经验
-------------------------------------------------------------------------------------------------------
请求数据每一个行需要以括号内的(--分隔符\r\n ) 进行分割,注意--是必须带的,例如:
"--" + boundary+"\r\n" 其中boundary 是自定义的分隔符
表单数据最后一项之后的分隔符是以 --\r\n结尾的,如下示例:
------WebKitFormBoundarydhy7IYZyMgmp2cLv--
实际上他是 "--" + boundary+"--\r\n" ,可以参考上文中代码 54行 --------------------------------------------------------------------------------------------- 读者如果觉得我讲的比较迷糊可以参考下下面这篇博文进行对比学习
http://blog.csdn.net/five3/article/details/7181521 听说Post传输数据有好几种形式哦,后续继续分析,欢迎拍砖
在使用 HttpWebRequest Post数据时候返回 400错误的更多相关文章
- HTTP请求中带有特殊字符"|",返回400错误
Java平台,服务器是Tomcat8,前端ajax访问服务器时,F12返回400错误,经分析,URL地址中get传参值里面含有“|“, Invalid character found and RFC ...
- 升级shiro1.6版本后导致附件上传失败,浏览器返回400错误
最新shiro发布了一个漏洞,凡是jar包在1.6版本的都会出现该漏洞,要修复该漏洞只能升级到shiro1.6版本 但是如果项目中url使用了;jsessionid这种方式的话 就会导致上传失败,浏览 ...
- mvn deploy返回400错误的几种可能
user credentials are wrong url to server is wrong user does not have access to the deployment reposi ...
- 解决webSocke客户端连接服务端返回400错误
原因: nginx使用了转发,头信息没设置全,问题出现在nginx的配置文件 解决办法: 修改nginx.conf配置文件,在linux终端敲入vim /etc/nginx/nginx.conf,找到 ...
- flask ajax发送请求返回400
在flaskWTF使用csrf保护后,一般提交form表单都需要一个隐藏的csrf 这样可以成功提交,但是使用ajax提交时就不能成功提交,会返回400错误,服务器无法理解请求,这样就需要新的方法解决 ...
- 由 POST 400 错误拔出来的萝卜
缘起 前段时间遇到扫描问题,好不容易拿到了扫描出来的数据,结果调用接口时弹了个 400(Bad request) 给我,匆匆找了点资料修补上线后,忐忑的心也可以安分点.然后,顺着这个 400 的萝卜, ...
- Tomcat 400错误 问题集锦
1.前后台参数类型不一致 上图错误提示就是客户端发送的请求不能找到你的具体的页面或者地址,这是Spring MVC抛出的错误,这样我们就要进行参数的检查,一定是JSP提交的参数和Controller里 ...
- nginx 设置client header 的大小与400错误
nginx默认的header长度上限是4k,如果超过了这个值 如果header头信息请求超过了,nginx会直接返回400错误可以通过以下2个参数来调整nginx的header上限 client_he ...
- post数据时报错:远程服务器返回错误: (400) 错误的请求。
网上查了多种方法,有不少说法,报400说是传的数据格式不对,最后的结论确实是数据格式不对. Content_Type为:application/json,配的数据格式有些麻烦,特别数多层,单层还好.例 ...
随机推荐
- MySQL:procedure, function, cursor,handler
Procedure & Function Procedure 语法: CREATE [DEFINER = { user | CURRENT_USER }] PROCEDURE sp_name ...
- java、easyui-combotree树形下拉选择框
最近一直在研究这个树形的下拉选择框,感觉非常的有用,现在整理下来供大家使用: 首先数据库的表架构设计和三级菜单联动的表结构是一样,(父子关系) 1.下面我们用hibernate建一下对应的额实体类: ...
- Spark SQL 之 Data Sources
#Spark SQL 之 Data Sources 转载请注明出处:http://www.cnblogs.com/BYRans/ 数据源(Data Source) Spark SQL的DataFram ...
- JS--实现简单轮播(一)
<!DOCTYPE html><html><head> <title></title> <meta charset=utf-8> ...
- android存储方式的应用场景
作为一个完整的应用程序,数据存储操作是必不可少的.因此,Android系统一共提供了四种数据存储方式.分别是:SharePreference.文件存储.SQLite. Content Provider ...
- jenkins邮件配置
jenkins自带的邮件管理太弱了,为了能按自定义的方式发送邮件,需要安装一个插件: Jenkins Email Extension Plugin. 1.配置邮件:通过"系统管理&quo ...
- tensorflow学习笔记二:入门基础
TensorFlow用张量这种数据结构来表示所有的数据.用一阶张量来表示向量,如:v = [1.2, 2.3, 3.5] ,如二阶张量表示矩阵,如:m = [[1, 2, 3], [4, 5, 6], ...
- JavaScript模板引擎artTemplate.js——结语
再次首先感谢模板的作者大神,再次放出github的地址:artTemplate性能卓越的js模板引擎 然后感谢博客园的一位前辈,他写的handlebars.js模板引擎教程,对我提供了很大的帮助,也是 ...
- 安装Anaconda
安装Anaconda来安装一切 spyder是python科学计算IDE,类似matlab.这是一个基于Qt的软件,如果使用pip install安装,会出现各种bug.pip install spy ...
- 1229【MySQL】性能优化之 Index Condition Pushdown
转自http://blog.itpub.net/22664653/viewspace-1210844/ [MySQL]性能优化之 Index Condition Pushdown2014-07-06 ...