【轉】asp.net(c#)使用HttpWebRequest附加攜帶請求參數以post方式模擬上傳大文件(以圖片為例)到Web伺服器端

来源:http://www.cnblogs.com/GodX/archive/2016/06/21/5604944.html
-Advertisement-
Play Games

原文地址:http://docode.top/Article/Detail/10002 目錄: 1、Http協議上傳文件(以圖片為例)請求報文體內容格式 2、完整版HttpWebRequest模擬上傳文件請求報文內容封裝 3、asp.net(c#)使用HttpWebRequest攜帶請求參數模擬上傳 ...


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

目錄:

1、Http協議上傳文件(以圖片為例)請求報文體內容格式

2、完整版HttpWebRequest模擬上傳文件請求報文內容封裝

3、asp.net(c#)使用HttpWebRequest攜帶請求參數模擬上傳文件封裝源碼下載

一、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;     }
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1、紅色感嘆號表示這個文件從伺服器上下載下來以後,在本地被修改過。這時執行提交操作就可以了。2、黃色感嘆號表示這個文件在提交的時候發現存在衝突,也就是說有別人在你提交之前對這個文件的同一個版本進行了修改。這時你需要查看這個文件的歷史日誌,和修改了這個文件的人進行溝通,將兩個人的修改內容合併,合併完成 ...
  • //方法一:只禁止多個進程運行 using System; using System.Collections.Generic; using System.Windows.Forms; namespace DuoYeMianIE { static class Program { /// <summar ...
  • 在編程中很可能使用到多級動態目錄,如果使用一般的方法將多級目錄綁定到Treeview就顯得非常局促了,所以,最好的辦法就是使用遞歸,使用遞歸就完全不用去考慮目錄的層次有多深.代碼其實很簡單. View Code 1 protected void Page_Load(object sender, Ev ...
  • 1bit 符號位,11bit 指數位,52bit 尾數位,±5.0E−324 到±1.79E+308 的浮點精度數字 15位有效數字 (char,nchar,text,ntext,varchar,nvarchar,xml) ...
  • 以下是示例的效果圖: WinForm的ListView控制項是可以分組顯示的,還可排序。可以把ListView的View屬性設置為Details完整項目請到下麵網址查找下載http://hovertree.com/hovertreescj/或者:http://hovertree.com/h/bjaf/ ...
  • 前面提到過這個網址:性能註意事項(實體框架) https://msdn.microsoft.com/zh-cn/library/cc853327.aspx註意版本: .NET Framework (current version) (還有一個其他版本, .NET Framework 4). 此文提到 ...
  • 1.ASP.NET Identity 適用所有類型的asp.net程式 ASP.NET MVC, Web Forms, Web Pages, Web API, and SignalR。 2.非常方便的擴展用戶數據欄位。只需一行代碼 設置好你的資料庫連接信息: 修改context的名稱: 打開試圖-》... ...
  • 一、前言 大多數系統裡面好像都有獲取消息的功能,但這些消息來源都不是實時的,比如你開兩個瀏覽器,用兩個不同的賬號登錄,用一個賬號給另外一個賬號發送消息,然而並不會實時收到消息,必須要自己手動F5刷新一下頁面才會顯示自己的消息,這樣感覺用戶體驗不太好。之前看了Learning hard關於Signal ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...