笔者有一个项目中用到了上传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. SQL Server 2012 新特性:服务角色管理

    数据库角色管理,已经可以使用alter role,create role和drop role. 2012增加了几个ddl语句,可以操作服务级别的角色管理,   CREATE SERVER ROLE 用 ...

  2. 分布式一致性算法--Raft

    前面一篇文章讲了Paxos协议,这篇文章讲它的姊妹篇Raft协议,相对于Paxos协议,Raft协议更为简单,也更容易工程实现.有关Raft协议和工程实现可以参考这个链接https://raft.gi ...

  3. GDB 完全教程

    一.简介 GDB是一个功能强大的调试器,它是一个自由软件,能够用在许多UNIX平台上.它同时也是Linux系统中的默认调试器.GDB已被移植到许多其他的计算机平台上,并且能够用于调试嵌入式实时系统.一 ...

  4. Linux下安装nginx

    一直会使用nginx,也学习了好多nginx知识.也在本地安装过nginx,这次是第一次在正式的环境安装nginx,把这些记录下来总结经验. 一.安装环境 操作系统:CentOS release 6. ...

  5. S5PV210_串行通信

    1.universal asynchronous reciver and transmitter 通用异步收发器 2.transmitter:由发送缓冲区和发送移位器构成.发送信息时,首先将信息编码( ...

  6. BZOJ 1251: 序列终结者 [splay]

    1251: 序列终结者 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 3778  Solved: 1583[Submit][Status][Discu ...

  7. Django基础,Day1 - 环境安装与pycharm创建django项目

    Django是一个高级Python Web框架,支持快速部署,清理和实用的设计.它可以被轻易部署和提供实用的组件,而开发人员只需要专注于写自己的应用程序,而不需要重复造轮子.并且Django是自由和开 ...

  8. 基于C/S架构的3D对战网络游戏C++框架 _04客户端详细设计与OpenGL、Qt基础

    本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): ...

  9. 混合使用UITabBarController和UINavigationController

    混合使用这两个控件的好处是我们可以在NavigationBar添加更多的东西,如标题,按钮等.让用户能够获得更多的信息. UITabBarController的属性ViewControllers接受以 ...

  10. CocoaPods 的简单快速安装方法

    CocoaPods 的简单快速安装方法(Setting up CocoaPods master repo 卡着不动,是因为淘宝镜像已经不能用了. 一.git clone方法安装cocoapods 镜像 ...