【转】asp.net(c#)使用HttpWebRequest附加携带请求参数以post方式模拟上传大文件(以图片为例)到Web服务器端_.NET_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > .NET > 【转】asp.net(c#)使用HttpWebRequest附加携带请求参数以post方式模拟上传大文件(以图片为例)到Web服务器端

【转】asp.net(c#)使用HttpWebRequest附加携带请求参数以post方式模拟上传大文件(以图片为例)到Web服务器端

 2016/6/22 5:33:46  冷水滩  程序员俱乐部  我要评论(0)
  • 摘要:原文地址:http://docode.top/Article/Detail/10002目录:1、Http协议上传文件(以图片为例)请求报文体内容格式2、完整版HttpWebRequest模拟上传文件请求报文内容封装3、asp.net(c#)使用HttpWebRequest携带请求参数模拟上传文件封装源码下载一、Http协议上传文件(以图片为例)请求报文体内容格式首先,我们来看下通过浏览器上传文件的请求报文内容格式,这里以本人自己写的实例为例,如下图。除了能上传图片(即:头像字段)
  • 标签:.net ASP.NET C# Web 使用 图片 上传 文件 net 方式 服务器 服务 HttpWebRequest HTTP

原文地址:http://docode.top/Article/Detail/10002

目录:

1、Http协议上传文件(以图片为例)请求报文体内容格式

2、完整版HttpWebRequest模拟上传文件请求报文内容封装

3、asp.net(c#)使用HttpWebRequest携带请求参数模拟上传文件封装源码下载

class="catalog-title">一、Http协议上传文件(以图片为例)请求报文体内容格式

    首先,我们来看下通过浏览器上传文件的请求报文内容格式,这里以本人自己写的实例为例,如下图。除了能上传图片(即:头像字段),还携带了用户名、密码两个字段,很好的诠释了http带参数上传文件的情形。点击提交按钮后,浏览器会将文件(即头像文件)二进制数据和用户名、密码以post方式发送至服务器。这时我们可以通过抓包工具(如:fiddler)(或者浏览器自带的开发者工具F12)查看请求报文内容。

HttpWebRequest携带参数上传图片等大文件

    通过抓包工具获取到携带参数上传文件请求报文体内容格式如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 POST /PostUploadHandler.ashx HTTP/1.1 Host: localhost:44187 Connection: keep-alive Content-Length: 19839 Cache-Control: max-age=0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Origin: http://localhost:44187 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36 Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryNSF3vGLxKBlk5kcB Referer: http://localhost:44187/UploadDemo.aspx Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.8     ------WebKitFormBoundaryNSF3vGLxKBlk5kcB Content-Disposition: form-data; name="userName"   admin ------WebKitFormBoundaryNSF3vGLxKBlk5kcB Content-Disposition: form-data; name="userPwd"   123456 ------WebKitFormBoundaryNSF3vGLxKBlk5kcB Content-Disposition: form-data; name="photo"; filename="1.png" Content-Type: image/png   <!--这一行是文件二进制数据--> ------WebKitFormBoundaryNSF3vGLxKBlk5kcB--

    1、请求头中有一个Content-Type参数(默认值:application/x-www-form-urlencoded),其中multipart/form-data值表示向服务器发送二进制数据,boundary表示请求体的分界线,服务器就是依靠分界线分割请求体来读取数据,此参数值可自定义

    2、请求体依靠boundary有规则的排列参数。每一行字符串后面包含一个换行符“\r\n”,有一个开始分界线(--boundary)和一个结束分界线(--boundary--),参数与参数之间通过--boundary分离,每一个参数的键(key)和值(value)之间包含一个空行即:“\r\n"。

 

二、完整版HttpWebRequest模拟上传文件请求报文内容封装

    通过上面介绍,我们已经清楚了解了http协议上传文件的POST请求报文内容格式,在.net中使用HttpWebRequest上传文件,我们只要按照此格式封装请求报文,即可实现携带参数上传功能了。

    为了方便扩展和维护,把所有请求参数(如上传地址url、携带参数、上传文件流等)封装到一个类中,代码如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 /// <summary> /// 上传文件 - 请求参数类 /// </summary> public class UploadParameterType {     public UploadParameterType()     {         FileNameKey = "fileName";         Encoding = Encoding.UTF8;         PostParameters = new Dictionary<stringstring>();     }     /// <summary>     /// 上传地址     /// </summary>     public string Url { getset; }     /// <summary>     /// 文件名称key     /// </summary>     public string FileNameKey { getset; }     /// <summary>     /// 文件名称value     /// </summary>     public string FileNameValue { getset; }     /// <summary>     /// 编码格式     /// </summary>     public Encoding Encoding { getset; }     /// <summary>     /// 上传文件的流     /// </summary>     public Stream UploadStream { getset; }     /// <summary>     /// 上传文件 携带的参数集合     /// </summary>     public IDictionary<stringstring> PostParameters { getset; }  }

    新建一个上传文件工具类(命名为:HttpUploadClient),在类中增加上传方法(命名为:Execute),如下所示:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 /// <summary> /// Http上传文件类 - HttpWebRequest封装 /// </summary> public class HttpUploadClient {     /// <summary>     /// 上传执行 方法     /// </summary>     /// <param name="parameter">上传文件请求参数</param>     public static string Execute(UploadParameterType parameter)     {               }     static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)     {         return true;     } }

    Post上传请求体参数是二进制格式的,我们只需要将参数根据以上报文体内容格式拼接好数据,存放在内存流里面,拼接完整后,将整个内存流转换成二进制格式写入到HttpWebRequest请求体中就行,下面我们来一步一步的拼接报文体内容。

    1、定义开始结束分界线boundary及拼接开始分界线:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public static string Execute(UploadParameterType parameter) {     using (MemoryStream memoryStream = new MemoryStream())     {         // 1.分界线         string boundary = string.Format("----{0}", DateTime.Now.Ticks.ToString("x")),       // 分界线可以自定义参数             beginBoundary = string.Format("--{0}\r\n", boundary),             endBoundary = string.Format("\r\n--{0}--\r\n", boundary);         byte[] beginBoundaryBytes = parameter.Encoding.GetBytes(beginBoundary),             endBoundaryBytes = parameter.Encoding.GetBytes(endBoundary);         // 2.组装开始分界线数据体 到内存流中         memoryStream.Write(beginBoundaryBytes, 0, beginBoundaryBytes.Length);         // ……     } }

    2、拼接附加携带参数:

1 2 3 4 5 6 7 8 9 10 11 // 3.组装 上传文件附加携带的参数 到内存流中 if (parameter.PostParameters != null && parameter.PostParameters.Count > 0) {     foreach (KeyValuePair<stringstring> keyValuePair in parameter.PostParameters)     {         string parameterHeaderTemplate = string.Format("Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}\r\n{2}", keyValuePair.Key, keyValuePair.Value, beginBoundary);         byte[] parameterHeaderBytes = parameter.Encoding.GetBytes(parameterHeaderTemplate);           memoryStream.Write(parameterHeaderBytes, 0, parameterHeaderBytes.Length);     } }

    3、拼接上传文件体及结束分界线boundary(需要注意的是Content-Type的值是:application/octet-stream):

1 2 3 4 5 6 7 8 9 10 11 12 13 14 // 4.组装文件头数据体 到内存流中 string fileHeaderTemplate = string.Format("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: application/octet-stream\r\n\r\n", parameter.FileNameKey, parameter.FileNameValue); byte[] fileHeaderBytes = parameter.Encoding.GetBytes(fileHeaderTemplate); memoryStream.Write(fileHeaderBytes, 0, fileHeaderBytes.Length); // 5.组装文件流 到内存流中 byte[] buffer = new byte[1024 * 1024 * 1]; int size = parameter.UploadStream.Read(buffer, 0, buffer.Length); while (size > 0) {     memoryStream.Write(buffer, 0, size);     size = parameter.UploadStream.Read(buffer, 0, buffer.Length); } // 6.组装结束分界线数据体 到内存流中 memoryStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);

    4、通过以上步骤,上传文件请求体内容数据已经拼接完成,接下来就是对HttpWebRequest对象的属性设置(如:请求地址Url,请求方法Method,Content-Type等),把整个上传文件请求体内存流写入到HttpWebRequest对象的请求体中,然后发起上传请求。如下源码:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 // 7.获取二进制数据 byte[] postBytes = memoryStream.ToArray(); // 8.HttpWebRequest 组装 HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(new Uri(parameter.Url, UriKind.RelativeOrAbsolute)); webRequest.Method = "POST"; webRequest.Timeout = 10000; webRequest.ContentType = string.Format("multipart/form-data; boundary={0}", boundary); webRequest.ContentLength = postBytes.Length; if (Regex.IsMatch(parameter.Url, "^https://")) {     ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;     ServicePointManager.ServerCertificateValidationCallback = CheckValidationResult; } // 9.写入上传请求数据 using (Stream requestStream = webRequest.GetRequestStream()) {     requestStream.Write(postBytes, 0, postBytes.Length);     requestStream.Close(); } // 10.获取响应 using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse()) {     using (StreamReader reader = new StreamReader(webResponse.GetResponseStream(), parameter.Encoding))     {         string body = reader.ReadToEnd();         reader.Close();         return body;     } }

    完整版HttpWebRequest模拟上传文件代码如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 /// <summary> /// Http上传文件类 - HttpWebRequest封装 /// </summary> public class HttpUploadClient {     /// <summary>     /// 上传执行 方法     /// </summary>     /// <param name="parameter">上传文件请求参数</param>     public static string Execute(UploadParameterType parameter)     {         using (MemoryStream memoryStream = new MemoryStream())         {             // 1.分界线             string boundary = string.Format("----{0}", DateTime.Now.Ticks.ToString("x")),       // 分界线可以自定义参数                 beginBoundary = string.Format("--{0}\r\n", boundary),                 endBoundary = string.Format("\r\n--{0}--\r\n", boundary);             byte[] beginBoundaryBytes = parameter.Encoding.GetBytes(beginBoundary),                 endBoundaryBytes = parameter.Encoding.GetBytes(endBoundary);             // 2.组装开始分界线数据体 到内存流中             memoryStream.Write(beginBoundaryBytes, 0, beginBoundaryBytes.Length);             // 3.组装 上传文件附加携带的参数 到内存流中             if (parameter.PostParameters != null && parameter.PostParameters.Count > 0)             {                 foreach (KeyValuePair<stringstring> keyValuePair in parameter.PostParameters)                 {                     string parameterHeaderTemplate = string.Format("Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}\r\n{2}", keyValuePair.Key, keyValuePair.Value, beginBoundary);                     byte[] parameterHeaderBytes = parameter.Encoding.GetBytes(parameterHeaderTemplate);                       memoryStream.Write(parameterHeaderBytes, 0, parameterHeaderBytes.Length);                 }             }             // 4.组装文件头数据体 到内存流中             string fileHeaderTemplate = string.Format("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: application/octet-stream\r\n\r\n", parameter.FileNameKey, parameter.FileNameValue);             byte[] fileHeaderBytes = parameter.Encoding.GetBytes(fileHeaderTemplate);             memoryStream.Write(fileHeaderBytes, 0, fileHeaderBytes.Length);             // 5.组装文件流 到内存流中             byte[] buffer = new byte[1024 * 1024 * 1];             int size = parameter.UploadStream.Read(buffer, 0, buffer.Length);             while (size > 0)             {                 memoryStream.Write(buffer, 0, size);                 size = parameter.UploadStream.Read(buffer, 0, buffer.Length);             }             // 6.组装结束分界线数据体 到内存流中             memoryStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);             // 7.获取二进制数据             byte[] postBytes = memoryStream.ToArray();             // 8.HttpWebRequest 组装             HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(new Uri(parameter.Url, UriKind.RelativeOrAbsolute));             webRequest.Method = "POST";             webRequest.Timeout = 10000;             webRequest.ContentType = string.Format("multipart/form-data; boundary={0}", boundary);             webRequest.ContentLength = postBytes.Length;             if (Regex.IsMatch(parameter.Url, "^https://"))             {                 ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;                 ServicePointManager.ServerCertificateValidationCallback = CheckValidationResult;             }             // 9.写入上传请求数据             using (Stream requestStream = webRequest.GetRequestStream())             {                 requestStream.Write(postBytes, 0, postBytes.Length);                 requestStream.Close();             }             // 10.获取响应             using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse())             {                 using (StreamReader reader = new StreamReader(webResponse.GetResponseStream(), parameter.Encoding))                 {                     string body = reader.ReadToEnd();                     reader.Close();                     return body;                 }             }         }     }     static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)     {         return true;     } }

    为了验证封装是否正确,可以写一个控制台应用程序来模拟Http协议上传文件(以图片为例),结果如图:

HttpWebRequest携带参数上传图片等大文件实例源码

三、asp.net(c#)使用HttpWebRequest携带请求参数模拟上传文件封装源码下载

    HttpWebRequest模拟上传文件封装源码

 

扫一扫获取百度网盘超级vip账号

 

发表评论
用户名: 匿名