笔者有一个项目中用到了上传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错误的更多相关文章

  1. HTTP请求中带有特殊字符"|",返回400错误

    Java平台,服务器是Tomcat8,前端ajax访问服务器时,F12返回400错误,经分析,URL地址中get传参值里面含有“|“, Invalid character found and RFC ...

  2. 升级shiro1.6版本后导致附件上传失败,浏览器返回400错误

    最新shiro发布了一个漏洞,凡是jar包在1.6版本的都会出现该漏洞,要修复该漏洞只能升级到shiro1.6版本 但是如果项目中url使用了;jsessionid这种方式的话 就会导致上传失败,浏览 ...

  3. mvn deploy返回400错误的几种可能

    user credentials are wrong url to server is wrong user does not have access to the deployment reposi ...

  4. 解决webSocke客户端连接服务端返回400错误

    原因: nginx使用了转发,头信息没设置全,问题出现在nginx的配置文件 解决办法: 修改nginx.conf配置文件,在linux终端敲入vim /etc/nginx/nginx.conf,找到 ...

  5. flask ajax发送请求返回400

    在flaskWTF使用csrf保护后,一般提交form表单都需要一个隐藏的csrf 这样可以成功提交,但是使用ajax提交时就不能成功提交,会返回400错误,服务器无法理解请求,这样就需要新的方法解决 ...

  6. 由 POST 400 错误拔出来的萝卜

    缘起 前段时间遇到扫描问题,好不容易拿到了扫描出来的数据,结果调用接口时弹了个 400(Bad request) 给我,匆匆找了点资料修补上线后,忐忑的心也可以安分点.然后,顺着这个 400 的萝卜, ...

  7. Tomcat 400错误 问题集锦

    1.前后台参数类型不一致 上图错误提示就是客户端发送的请求不能找到你的具体的页面或者地址,这是Spring MVC抛出的错误,这样我们就要进行参数的检查,一定是JSP提交的参数和Controller里 ...

  8. nginx 设置client header 的大小与400错误

    nginx默认的header长度上限是4k,如果超过了这个值 如果header头信息请求超过了,nginx会直接返回400错误可以通过以下2个参数来调整nginx的header上限 client_he ...

  9. post数据时报错:远程服务器返回错误: (400) 错误的请求。

    网上查了多种方法,有不少说法,报400说是传的数据格式不对,最后的结论确实是数据格式不对. Content_Type为:application/json,配的数据格式有些麻烦,特别数多层,单层还好.例 ...

随机推荐

  1. Eclipse创建Maven工程报错

    问题 用Eclipse创建maven工程的时候,总是会报错,例如提示: Unable to create project from archetype [org.apache.maven.archet ...

  2. sql select 1-10的数字

    SELECT V FROM (   VALUES (1), (2), (3), (4), (5),          (6), (7), (8), (9), (10) ) [1 to 10](V)

  3. shiro-简介

    简介: Apache Shiro 是Java的一个安全(权限)框架. Shiro可以非常容易的开发出足够好的应用,其不仅可以用在JavaSE环境,也可以用在JavaEE环境. Shiro可以完成:认证 ...

  4. [LeetCode] Verify Preorder Serialization of a Binary Tree 验证二叉树的先序序列化

    One way to serialize a binary tree is to use pre-oder traversal. When we encounter a non-null node, ...

  5. python获取父类的子类(遍历,递归),并循环执行所有子类的某一方法

    前言 换了新工作,踏足于python语言的开发,也把自己的学习过程记录下来. 一,递归获取某一父类的所有子类 all_subclasses = {'0': '0'} def get_all_class ...

  6. 2016BUAA校赛决赛

    A. 题意:有n个点,n-1条边,1-2-3-4-5-...-n,每条边都有权值,代表走这条边的时间,时刻0一个人在点1,问从时刻1~m,有哪些时刻这个人可能走到n点 分析:将每条边当作物品,可以选1 ...

  7. anaconda

    python 集成环境 anaconda的使用 https://www.zhihu.com/question/35757251

  8. JavaScript的基本语法

    1.脚本的基本结构如下: <script language="JavaScript"> <!--JavaScript语句:--> </script&g ...

  9. 让Visual Studio 2013为你自动生成XML反序列化的类

    Visual Sutdio 2013增加了许多新功能,其中很多都直接提高了对代码编辑的便利性.如: 1. 在代码编辑界面的右侧滚动条上显示不同颜色的标签,让开发人员可以对所编辑文档的修改.查找.定位情 ...

  10. 关于Django 错误 查询之后结果序列化出现的问题is not JSON serializable

    由于查询出来的结果是instance (实例 /对象) 无法实例化, 在model结果加 .value()