From 17ab7e7b595aba0817ef0425c9df82020bbee33d Mon Sep 17 00:00:00 2001 From: Kevin <1985088337@qq.com> Date: Sun, 12 Feb 2017 19:19:38 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E8=BF=81=E7=A7=BB=E8=87=B3Ht?= =?UTF-8?q?tpClient=E6=9E=B6=E6=9E=84=E4=B8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OSS.Http.ConsoleTest/App.config | 6 - OSS.Http.ConsoleTest/Program.cs | 118 - .../Properties/AssemblyInfo.cs | 36 - OSS.Http.NET45.sln | 22 + OSS.Http.sln | 16 +- OSS.Http/Connect/HttpBase.cs | 510 ---- OSS.Http/Connect/OsRest.cs | 262 ++ OSS.Http/Connect/RestHttp.Async.cs | 27 - OSS.Http/Connect/RestHttp.Sync.cs | 64 - OSS.Http/Enum.cs | 22 +- OSS.Http/HttpUtil.cs | 35 +- OSS.Http/Interface/IHttp.cs | 24 - OSS.Http/Models/FileParameter.cs | 2 - OSS.Http/Models/HttpRequest.cs | 87 +- OSS.Http/Models/HttpResponse.cs | 116 - OSS.Http/Models/Parameter.cs | 3 - .../OSS.Http.NET45.csproj | 40 +- OSS.Http/OSS.Http.NET45.project.json | 8 + OSS.Http/OSS.Http.csproj | 37 +- OSS.Http/project.json | 10 + OSS.Http/project.lock.json | 2639 +++++++++++++++++ 21 files changed, 3058 insertions(+), 1026 deletions(-) delete mode 100644 OSS.Http.ConsoleTest/App.config delete mode 100644 OSS.Http.ConsoleTest/Program.cs delete mode 100644 OSS.Http.ConsoleTest/Properties/AssemblyInfo.cs create mode 100644 OSS.Http.NET45.sln delete mode 100644 OSS.Http/Connect/HttpBase.cs create mode 100644 OSS.Http/Connect/OsRest.cs delete mode 100644 OSS.Http/Connect/RestHttp.Async.cs delete mode 100644 OSS.Http/Connect/RestHttp.Sync.cs delete mode 100644 OSS.Http/Interface/IHttp.cs delete mode 100644 OSS.Http/Models/HttpResponse.cs rename OSS.Http.ConsoleTest/OSS.Http.ConsoleTest.csproj => OSS.Http/OSS.Http.NET45.csproj (63%) create mode 100644 OSS.Http/OSS.Http.NET45.project.json create mode 100644 OSS.Http/project.json create mode 100644 OSS.Http/project.lock.json diff --git a/OSS.Http.ConsoleTest/App.config b/OSS.Http.ConsoleTest/App.config deleted file mode 100644 index 8e15646..0000000 --- a/OSS.Http.ConsoleTest/App.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/OSS.Http.ConsoleTest/Program.cs b/OSS.Http.ConsoleTest/Program.cs deleted file mode 100644 index bc0d3e5..0000000 --- a/OSS.Http.ConsoleTest/Program.cs +++ /dev/null @@ -1,118 +0,0 @@ -using System; -using System.IO; -using System.Threading; -using OSS.Http.Models; - -namespace OSS.Http.ConsoleTest -{ - class Program - { - static void Main(string[] args) - { - Console.WriteLine("请输入请求地址(quit 直接退出):"); - string url = string.Empty; - while ((url=Console.ReadLine())!="quit") - { - if (!string.IsNullOrEmpty(url)) - { - Console.WriteLine("输入 async 执行异步请求,输入 sync 执行同步请求:"); - string cmd = Console.ReadLine(); - if (cmd == "async") - { - AsyncHttp(url); - } - else if (cmd == "sync") - { - SyncHttp(url); - } - } - Console.WriteLine("请输入请求地址:"); - } - } - - private static void SyncHttp(string url) - { - if (!string.IsNullOrEmpty(url)) - { - OsHttpRequest request = new OsHttpRequest(); - request.AddressUrl = url; - request.HttpMothed = HttpMothed.POST; - request.Parameters.Add(new Parameter("name", "test", ParameterType.Form)); - FileStream file_stream = null; - try - { - - file_stream = new FileStream("E:\\test.txt", FileMode.Open, FileAccess.Read); - - //byte[] bites = new byte[file_stream.Length]; - - //using (file_stream) - //{ - // file_stream.Read(bites, 0, bites.Length); - //} - - FileParameter file = new FileParameter("test", file_stream, "test_file", contentType: "text/plain"); - request.FileParameterList.Add(file); - - var response = HttpUtil.ExecuteSync(request); - - Console.WriteLine(response.Content); - - Console.WriteLine("请求结束!!!"); - } - catch (Exception) - { - } - finally - { - if (file_stream != null) - file_stream.Close(); - } - - } - } - - - private static void AsyncHttp(string url) - { - if (!string.IsNullOrEmpty(url)) - { - OsHttpRequest request = new OsHttpRequest(); - request.AddressUrl = url; - request.HttpMothed = HttpMothed.POST; - request.Parameters.Add(new Parameter("name", "test", ParameterType.Form)); - FileStream file_stream = null; - try - { - file_stream = new FileStream("E:\\test.txt", FileMode.Open, FileAccess.Read); - - FileParameter file = new FileParameter("test", file_stream, "test_file", contentType: "text/plain"); - request.FileParameterList.Add(file); - Console.WriteLine(string.Format("当前主线程ID:{0}", Thread.CurrentThread.ManagedThreadId)); - HttpUtil.ExecuteAsync(request, res => - { - Console.WriteLine("进入异步响应 :"); - Console.WriteLine(res.Content); - Console.WriteLine(" "); - Console.WriteLine(string.Format("当前子线程ID:{0}", Thread.CurrentThread.ManagedThreadId)); - Console.WriteLine("异步结束 "); - }); - Console.WriteLine(string.Format("当前主线程ID:{0}", Thread.CurrentThread.ManagedThreadId)); - } - catch (Exception) - { - - } - finally - { - if (file_stream != null) - file_stream.Close(); - } - - } - } - - - - } -} diff --git a/OSS.Http.ConsoleTest/Properties/AssemblyInfo.cs b/OSS.Http.ConsoleTest/Properties/AssemblyInfo.cs deleted file mode 100644 index 3c8456a..0000000 --- a/OSS.Http.ConsoleTest/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("OSS.Http.ConsoleTest")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Microsoft")] -[assembly: AssemblyProduct("OSS.Http.ConsoleTest")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2013")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("1f56fe4b-8d19-4842-8019-0cab316444c9")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/OSS.Http.NET45.sln b/OSS.Http.NET45.sln new file mode 100644 index 0000000..ec7db6a --- /dev/null +++ b/OSS.Http.NET45.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OSS.Http.NET45", "OSS.Http\OSS.Http.NET45.csproj", "{5A831C5B-8D82-4A6A-A555-3E04847455D1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5A831C5B-8D82-4A6A-A555-3E04847455D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5A831C5B-8D82-4A6A-A555-3E04847455D1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5A831C5B-8D82-4A6A-A555-3E04847455D1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5A831C5B-8D82-4A6A-A555-3E04847455D1}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/OSS.Http.sln b/OSS.Http.sln index 2eda144..09dc39f 100644 --- a/OSS.Http.sln +++ b/OSS.Http.sln @@ -3,9 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OSS.Http", "OSS.Http\OSS.Http.csproj", "{5A831C5B-8D82-4A6A-A555-3E04847455D1}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OSS.Http.ConsoleTest", "OSS.Http.ConsoleTest\OSS.Http.ConsoleTest.csproj", "{0504F610-BD59-45B5-988C-BFFE15AAAC82}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OSS.Http", "OSS.Http\OSS.Http.csproj", "{7AE49C75-D715-4688-8E11-A8334C461608}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +11,10 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {5A831C5B-8D82-4A6A-A555-3E04847455D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5A831C5B-8D82-4A6A-A555-3E04847455D1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5A831C5B-8D82-4A6A-A555-3E04847455D1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5A831C5B-8D82-4A6A-A555-3E04847455D1}.Release|Any CPU.Build.0 = Release|Any CPU - {0504F610-BD59-45B5-988C-BFFE15AAAC82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0504F610-BD59-45B5-988C-BFFE15AAAC82}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0504F610-BD59-45B5-988C-BFFE15AAAC82}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0504F610-BD59-45B5-988C-BFFE15AAAC82}.Release|Any CPU.Build.0 = Release|Any CPU + {7AE49C75-D715-4688-8E11-A8334C461608}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7AE49C75-D715-4688-8E11-A8334C461608}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7AE49C75-D715-4688-8E11-A8334C461608}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7AE49C75-D715-4688-8E11-A8334C461608}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/OSS.Http/Connect/HttpBase.cs b/OSS.Http/Connect/HttpBase.cs deleted file mode 100644 index 7d6aa6d..0000000 --- a/OSS.Http/Connect/HttpBase.cs +++ /dev/null @@ -1,510 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Net; -using System.Text; -using System.Web; -using OSS.Http.Models; - -namespace OSS.Http.Connect -{ - /// - /// 请求基类 - /// - public abstract class HttpBase - { - private const string _lineBreak = "\r\n"; - private static readonly Encoding _defaultEncoding = Encoding.UTF8; - protected IDictionary> _notCanAddHeaderDictionary = null; - public HttpBase() - { - _notCanAddHeaderDictionary = new Dictionary>(StringComparer.InvariantCultureIgnoreCase); - } - - - /// - /// 配置请求 - /// - /// - protected virtual HttpWebRequest ConfigureWebRequest(OsHttpRequest request) - { - Uri uri = BuildUri(request); // 创建url请求 - var webRequest = (HttpWebRequest)WebRequest.Create(uri); - - ServicePointManager.Expect100Continue = false; - if (request.IsDecompres) - { - webRequest.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip | DecompressionMethods.None; - } - - webRequest.Method = request.HttpMothed.ToString(); - - if (request.TimeOutMilSeconds>0) - { - webRequest.Timeout = request.TimeOutMilSeconds; - webRequest.ReadWriteTimeout = request.TimeOutMilSeconds; - } - - if (!request.HasFile) - { - webRequest.ContentLength = 0; - } - - webRequest.ContentType = "application/x-www-form-urlencoded"; //添加一个默认类型,具体自定义可以在后边重写 - - PrepareHeaders(webRequest, request); // 添加头部信息 - PrepareCookies(webRequest, request); // 添加cookie信息 - - request.CustomPropertySetting?.Invoke(webRequest); - - return webRequest; - } - - - - /// - /// 创建请求的 Url 对象 - /// - /// 请求的对象实体 - /// 返回的 System.Uri 对象 - protected virtual Uri BuildUri(OsHttpRequest request) - { - string urlAddress = request.AddressUrl; - if (string.IsNullOrEmpty(urlAddress)) - { - throw new ArgumentNullException("无效的请求,请求对象中的 UrlAddress 不能为空"); - } - return new Uri(urlAddress); - } - - - #region 准备模块 - - /// - /// 准备请求的 头部 数据 - /// - /// - /// - protected virtual void PrepareHeaders(HttpWebRequest webRequest, OsHttpRequest request) - { - foreach (var header in request.HeaderParameters) - { - if (_notCanAddHeaderDictionary.ContainsKey(header.Name)) - { - _notCanAddHeaderDictionary[header.Name].Invoke(webRequest, header.Value.ToString()); - } - else - { - webRequest.Headers.Add(header.Name, header.Value.ToString()); - } - - } - } - - /// - /// 准备请求的 cookie 数据 - /// - /// - /// - protected virtual void PrepareCookies(HttpWebRequest webRequest, OsHttpRequest request) - { - webRequest.CookieContainer = new CookieContainer(); - - foreach (var httpCookie in request.CookieParameters) - { - var cookie = new Cookie - { - Name = httpCookie.Name, - Value = httpCookie.Value.ToString(), - Domain =string.IsNullOrEmpty(httpCookie.Domain)? webRequest.RequestUri.Host:httpCookie.Domain - }; - webRequest.CookieContainer.Add(cookie); - } - } - #endregion - - - /// - /// 准备请求的 内容 数据 === 同步 - /// - /// HttpWebRequest请求 - protected virtual void SendBodyDataSync(HttpWebRequest webRequest, OsHttpRequest request) - { - string boundary = GetBoundary(); - if (request.HasFile) - { - webRequest.ContentType = GetMultipartFormContentType(boundary); - using (var webRequestStream = webRequest.GetRequestStream()) - { - WriteMultipartFormData(webRequestStream, request, boundary); - } - } - else - { - string data = EncodeFormParameters(request); - if (!string.IsNullOrEmpty(data)) - { - var bytes = _defaultEncoding.GetBytes(data); - webRequest.ContentLength = bytes.Length; - using (var webRequestStream = webRequest.GetRequestStream()) - { - webRequestStream.Write(bytes, 0, bytes.Length); - } - } - } - } - - /// - /// 准备请求的 内容 数据 === 异步 - /// - /// HttpWebRequest请求 - /// - /// - protected virtual void SendBodyDataAsyncAndCallBack(HttpWebRequest webRequest, OsHttpRequest request, - Action action) - { - if (request.HttpMothed == HttpMothed.POST && request.FormParameters.Count > 0 || request.HasFile) - { - if (!request.HasFile) - { - webRequest.ContentLength = _defaultEncoding.GetByteCount(EncodeFormParameters(request)); - } - webRequest.BeginGetRequestStream(ar => RquestStreamCallBack(ar, request, action), webRequest); - } - else - { - webRequest.BeginGetResponse(ar => ResponseCallBackAsync(ar, action), webRequest); - } - } - - /// - /// 异步请求处理 - /// - /// - /// - /// - private void RquestStreamCallBack(IAsyncResult result, OsHttpRequest request, - Action action) - { - - - HttpWebRequest webRequest = result.AsyncState as HttpWebRequest; - - if (request.HasFile) - { - string boundary = GetBoundary(); - - webRequest.ContentType = GetMultipartFormContentType(boundary); - - using (var webRequestStream = webRequest.EndGetRequestStream(result)) - { - WriteMultipartFormData(webRequestStream, request, boundary); - } - } - else - { - var bytes = _defaultEncoding.GetBytes(EncodeFormParameters(request)); - - using (var webRequestStream = webRequest.EndGetRequestStream(result)) - { - webRequestStream.Write(bytes, 0, bytes.Length); - } - } - - webRequest.BeginGetResponse(ar => ResponseCallBackAsync(ar, action), webRequest); - } - - /// - /// 异步响应处理 - /// - /// - /// - private void ResponseCallBackAsync(IAsyncResult result, Action action) - { - var response = new OsHttpResponse(); - - HttpWebResponse web_response = null; - try - { - var webRequest = (HttpWebRequest)result.AsyncState; - web_response = webRequest.EndGetResponse(result) as HttpWebResponse; - } - catch (WebException ex) - { - if (ex.Status == WebExceptionStatus.RequestCanceled) - { - throw ex; - } - if (ex.Response is HttpWebResponse) - { - response.ResponseStatus = ResponseStatus.ErrorButResponse; - web_response = ex.Response as HttpWebResponse; - } - else - { - throw ex; - } - } - - ExtractResponseData(response, web_response); - - if (action != null) - { - action(response); - } - - if (web_response != null) - web_response.Close(); - } - - #region 请求数据的 内容 处理 - - #region 处理带文件上传的数据处理 - /// - /// 创建 请求 分割界限 - /// - /// - protected static string GetBoundary() - { - string pattern = "abcdefghijklmnopqrstuvwxyz0123456789"; - StringBuilder boundaryBuilder = new StringBuilder(); - Random rnd = new Random(); - for (int i = 0; i < 10; i++) - { - var index = rnd.Next(pattern.Length); - boundaryBuilder.Append(pattern[index]); - } - return string.Format("-----------------------------{0}", boundaryBuilder.ToString()); - } - - /// - /// 返回含文件请求的ContentType - /// - /// - /// 返回 WebRequest 的 ContenType 信息 - protected static string GetMultipartFormContentType(string boundary) - { - return string.Format("multipart/form-data; boundary={0}", boundary); - } - - /// - /// 写入 Form 的内容值 【 非文件参数 + 文件头 + 文件参数(内部完成) + 请求结束符 】 - /// - /// - /// - protected void WriteMultipartFormData(Stream webRequestStream, OsHttpRequest request, string boundary) - { - var formparas = request.FormParameters; - foreach (var param in formparas) - { - //写入form表单中的非文件数据 - WriteStringTo(webRequestStream, GetMultipartFormData(param, boundary)); - } - foreach (var file in request.FileParameterList) - { - //文件头 - WriteStringTo(webRequestStream, GetMultipartFileHeader(file, boundary)); - //文件内容 - file.Writer(webRequestStream); - //文件结尾 - WriteStringTo(webRequestStream, _lineBreak); - } - //写入整个请求的底部信息 - WriteStringTo(webRequestStream, GetMultipartFooter(boundary)); - } - - /// - /// 写入 Form 的内容值(非文件参数) - /// - /// - /// - /// - protected static string GetMultipartFormData(Parameter param, string boundary) - { - return string.Format("--{0}{3}Content-Disposition: form-data; name=\"{1}\"{3}{3}{2}{3}", - boundary, param.Name, param.Value, _lineBreak); - } - - /// - /// 写入 Form 的内容值(文件头) - /// - /// - /// - /// - protected static string GetMultipartFileHeader(FileParameter file, string boundary) - { - return string.Format("--{0}{4}Content-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"{4}Content-Type: {3}{4}{4}", - boundary, file.Name, file.FileName, file.ContentType ?? "application/octet-stream", _lineBreak); - } - - /// - /// 写入 Form 的内容值 (请求结束符) - /// - /// - /// - protected static string GetMultipartFooter(string boundary) - { - return string.Format("--{0}--{1}", boundary, _lineBreak); - } - #endregion - - #region 不包含文件的数据处理(正常 get/post 请求) - /// - /// 写入请求的内容信息 (非文件上传请求) - /// - /// - /// - protected static string EncodeFormParameters(OsHttpRequest request) - { - var formstring = new StringBuilder(); - foreach (var p in request.FormParameters) - { - if (formstring.Length > 1) - formstring.Append("&"); - formstring.AppendFormat("{0}={1}", p.Name, p.Value); - } - if (!string.IsNullOrEmpty(request.CustomBody)) - { - if (formstring.Length > 1) - formstring.Append("&"); - formstring.Append(request.CustomBody); - } - return formstring.ToString(); - } - #endregion - - #endregion - - #region 请求返回 -- 返回数据的处理 - - /// - /// 返回自定义 - /// - /// 传入 webrequest 对象 - /// 需要返回的自定义 response 对象 - /// - protected virtual void GetResponse(HttpWebRequest request, ref OsHttpResponse response) - { - response.ResponseStatus = ResponseStatus.None; - - bool isErrorButResponse; - var webResponse = GetHttpResponse(request, out isErrorButResponse); - - ExtractResponseData(response, webResponse); - - if (isErrorButResponse) - response.ResponseStatus = ResponseStatus.ErrorButResponse; - - } - - /// - /// 获取远程请求响应 - /// - /// 请求对象 - /// 请求返回是否正常 - /// - private static HttpWebResponse GetHttpResponse(HttpWebRequest request, out bool isErrorButResponse) - { - HttpWebResponse webResponse = null; - isErrorButResponse = false; - try - { - webResponse = (HttpWebResponse)request.GetResponse(); - } - catch (WebException ex) - { - if (ex.Response is HttpWebResponse) - { - isErrorButResponse = true; - webResponse = ex.Response as HttpWebResponse; - } - else - throw; - } - return webResponse; - } - - - /// - /// 填充自定义 response 值 - /// - /// - /// - private static void ExtractResponseData(OsHttpResponse response, HttpWebResponse webResponse) - { - using (webResponse) - { - response.ContentEncoding = webResponse.ContentEncoding; - response.Server = webResponse.Server; - response.ContentType = webResponse.ContentType; - response.ContentLength = webResponse.ContentLength; - - response.StatusCode = webResponse.StatusCode; - response.StatusDescription = webResponse.StatusDescription; - response.ResponseUri = webResponse.ResponseUri; - response.ResponseStatus = ResponseStatus.Completed; - - response.RawBytes = ReadAsBytes(webResponse.GetResponseStream()); - - if (webResponse.Cookies != null) - { - foreach (Cookie cookie in webResponse.Cookies) - { - HttpCookie recookie = new HttpCookie(cookie.Name); - recookie.Domain = cookie.Domain; - recookie.Expires = cookie.Expires; - recookie.HttpOnly = cookie.HttpOnly; - recookie.Path = cookie.Path; - recookie.Secure = cookie.Secure; - recookie.Value = cookie.Value; - response.Cookies.Add(recookie); - } - } - - foreach (var headerName in webResponse.Headers.AllKeys) - { - var headerValue = webResponse.Headers[headerName]; - response.Headers.Add(new Parameter { Name = headerName, Value = headerValue }); - } - webResponse.Close(); - } - } - - /// - /// 流转化成字节 - /// - /// 要转化的流 - /// byte[] - protected static byte[] ReadAsBytes(Stream input) - { - byte[] buffer = new byte[16 * 1024]; - using (MemoryStream ms = new MemoryStream()) - { - int read; - while ((read = input.Read(buffer, 0, buffer.Length)) > 0) - { - ms.Write(buffer, 0, read); - } - return ms.ToArray(); - } - } - #endregion - - #region 请求辅助方法 - /// - /// 写入数据方法(将数据写入 webrequest) - /// - /// - /// - protected static void WriteStringTo(Stream stream, string toWrite) - { - var bytes = _defaultEncoding.GetBytes(toWrite); - stream.Write(bytes, 0, bytes.Length); - } - - protected virtual void AddStaticHeaderDictionary() - { - } - #endregion - } -} diff --git a/OSS.Http/Connect/OsRest.cs b/OSS.Http/Connect/OsRest.cs new file mode 100644 index 0000000..ee9ee10 --- /dev/null +++ b/OSS.Http/Connect/OsRest.cs @@ -0,0 +1,262 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using OSS.Http.Models; + +namespace OSS.Http.Connect +{ + /// + /// 请求基类 + /// + public class OsRest:HttpClient + { + private const string _lineBreak = "\r\n"; + private static readonly Encoding _defaultEncoding = Encoding.UTF8; + + public OsRest():this(new HttpClientHandler(),true) + { + } + public OsRest(HttpMessageHandler handler) + : this(handler,true) + { + } + public OsRest(HttpMessageHandler handler,bool disposeHandler) : base(handler, disposeHandler) + { + } + + /// + /// 执行请求方法 + /// + /// + /// + /// + /// + public Task RestSend(OsHttpRequest request, + HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead, + CancellationToken cancellationToken = new CancellationToken()) + { + var reqMsg = ConfigureReqMsg(request); + + if (request.TimeOutMilSeconds > 0) + this.Timeout = TimeSpan.FromMilliseconds(request.TimeOutMilSeconds); + + return SendAsync(reqMsg, completionOption, cancellationToken); + } + + + #region 配置 ReqMsg信息 + + /// + /// 配置请求 + /// + /// + public HttpRequestMessage ConfigureReqMsg(OsHttpRequest request) + { + var reqMsg = new HttpRequestMessage(); + + reqMsg.RequestUri = ConfigReqUriMsg(request); + reqMsg.Method = new HttpMethod(request.HttpMothed.ToString()); + reqMsg.Headers.Add("Content-Type", "application/x-www-form-urlencoded"); // 默认补充,如果头参数中已设置,后边会覆盖 + + //ConfigReqHeadersMsg(reqMsg.Headers, request); // 添加头部信息 + request.HeaderSetting?.Invoke(reqMsg.Headers); + ConfigReqContent(reqMsg,request); // 配置内容 + + return reqMsg; + } + + /// + /// 创建请求的 Url 对象 + /// + /// 请求的对象实体 + /// 返回的 System.Uri 对象 + private Uri ConfigReqUriMsg(OsHttpRequest request) + { + if (string.IsNullOrEmpty(request.AddressUrl)) + { + throw new ArgumentNullException(nameof(request), "无效的请求,请求对象中的 UrlAddress 不能为空"); + } + string urlAddress = request.AddressUrl; + + var queryPara = GetReqParameters(request, ParameterType.Query); + urlAddress = queryPara.Aggregate(urlAddress, (current, p) => string.Concat(current, current.IndexOf("?", StringComparison.CurrentCultureIgnoreCase) < 0 ? "?" : "&", p.ToString())); + + + return new Uri(urlAddress); + } + + /// + /// 配置使用的cotent + /// + /// + /// + /// + private void ConfigReqContent(HttpRequestMessage reqMsg, OsHttpRequest req) + { + //var reqContent=new StreamContent(); + var contentStream = new MemoryStream(); + + if (req.HasFile) + { + string boundary = GetBoundary(); + WriteMultipartFormData(contentStream, req, boundary); + } + else + { + string data = GetNormalFormData(req); + if (!string.IsNullOrEmpty(data)) + { + var bytes = _defaultEncoding.GetBytes(data); + contentStream.Write(bytes, 0, bytes.Length); + } + } + reqMsg.Content = new StreamContent(contentStream); + } + #endregion + + + #region 请求数据的 内容 处理 + + #region 处理带文件上传的数据处理 + /// + /// 创建 请求 分割界限 + /// + /// + private static string GetBoundary() + { + string pattern = "abcdefghijklmnopqrstuvwxyz0123456789"; + StringBuilder boundaryBuilder = new StringBuilder(); + Random rnd = new Random(); + for (int i = 0; i < 10; i++) + { + var index = rnd.Next(pattern.Length); + boundaryBuilder.Append(pattern[index]); + } + return string.Format("-----------------------------{0}", boundaryBuilder.ToString()); + } + + ///// + ///// 返回含文件请求的ContentType + ///// + ///// + ///// 返回 WebRequest 的 ContenType 信息 + //private static string GetMultipartFormContentType(string boundary) + //{ + // return string.Format("multipart/form-data; boundary={0}", boundary); + //} + + /// + /// 写入 Form 的内容值 【 非文件参数 + 文件头 + 文件参数(内部完成) + 请求结束符 】 + /// + /// + /// + private void WriteMultipartFormData(Stream webRequestStream, OsHttpRequest request, string boundary) + { + var formparas =GetReqParameters(request,ParameterType.Form); + foreach (var param in formparas) + { + //写入form表单中的非文件数据 + WriteStringTo(webRequestStream, GetMultipartFormData(param, boundary)); + } + foreach (var file in request.FileParameterList) + { + //文件头 + WriteStringTo(webRequestStream, GetMultipartFileHeader(file, boundary)); + //文件内容 + file.Writer(webRequestStream); + //文件结尾 + WriteStringTo(webRequestStream, _lineBreak); + } + //写入整个请求的底部信息 + WriteStringTo(webRequestStream, GetMultipartFooter(boundary)); + } + + /// + /// 写入 Form 的内容值(非文件参数) + /// + /// + /// + /// + private static string GetMultipartFormData(Parameter param, string boundary) + { + return string.Format("--{0}{3}Content-Disposition: form-data; name=\"{1}\"{3}{3}{2}{3}", + boundary, param.Name, param.Value, _lineBreak); + } + + /// + /// 写入 Form 的内容值(文件头) + /// + /// + /// + /// + private static string GetMultipartFileHeader(FileParameter file, string boundary) + { + return string.Format("--{0}{4}Content-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"{4}Content-Type: {3}{4}{4}", + boundary, file.Name, file.FileName, file.ContentType ?? "application/octet-stream", _lineBreak); + } + + /// + /// 写入 Form 的内容值 (请求结束符) + /// + /// + /// + private static string GetMultipartFooter(string boundary) + { + return string.Format("--{0}--{1}", boundary, _lineBreak); + } + #endregion + + #region 不包含文件的数据处理(正常 get/post 请求) + /// + /// 写入请求的内容信息 (非文件上传请求) + /// + /// + /// + private static string GetNormalFormData(OsHttpRequest request) + { + var formParas = GetReqParameters(request, ParameterType.Form); + var formstring = new StringBuilder(); + foreach (var p in formParas) + { + if (formstring.Length > 1) + formstring.Append("&"); + formstring.AppendFormat("{0}={1}", p.Name, p.Value); + } + if (!string.IsNullOrEmpty(request.CustomBody)) + { + if (formstring.Length > 1) + formstring.Append("&"); + formstring.Append(request.CustomBody); + } + return formstring.ToString(); + } + #endregion + + #endregion + + + #region 请求辅助方法 + /// + /// 写入数据方法(将数据写入 webrequest) + /// + /// + /// + private static void WriteStringTo(Stream stream, string toWrite) + { + var bytes = _defaultEncoding.GetBytes(toWrite); + stream.Write(bytes, 0, bytes.Length); + } + + + private static List GetReqParameters(OsHttpRequest request,ParameterType type) + { + return request.Parameters.Where(p => p.Type == type).ToList() ?? new List(); + } + #endregion + } +} diff --git a/OSS.Http/Connect/RestHttp.Async.cs b/OSS.Http/Connect/RestHttp.Async.cs deleted file mode 100644 index 0dac62b..0000000 --- a/OSS.Http/Connect/RestHttp.Async.cs +++ /dev/null @@ -1,27 +0,0 @@ -using OSS.Http.Interface; -using OSS.Http.Models; -using System; -using System.Net; - -namespace OSS.Http.Connect -{ - internal partial class RestHttp - { - public void ExecuteAsync(OsHttpRequest request, Action action) - { - OsHttpResponse response = new OsHttpResponse(); - - if (string.IsNullOrEmpty(request.AddressUrl) - || request.HttpMothed == HttpMothed.None) - { - throw new ArgumentException("对不起,请求出错,请检查参数等设置(地址,请求方式等)!", "request"); - - } - - HttpWebRequest webrequest = ConfigureWebRequest(request); - - SendBodyDataAsyncAndCallBack(webrequest, request, action); - - } - } -} diff --git a/OSS.Http/Connect/RestHttp.Sync.cs b/OSS.Http/Connect/RestHttp.Sync.cs deleted file mode 100644 index f9a8783..0000000 --- a/OSS.Http/Connect/RestHttp.Sync.cs +++ /dev/null @@ -1,64 +0,0 @@ -using OSS.Http.Interface; -using OSS.Http.Models; -using System; -using System.Net; - -namespace OSS.Http.Connect -{ - internal partial class RestHttp : HttpBase, IHttp - { - public RestHttp() - { - AddStaticHeaderDictionary(); - } - - /// - /// 同步的请求方式 - /// - /// 请求的参数 - /// 自定义的Response结果 - public OsHttpResponse ExecuteSync(OsHttpRequest request) - { - OsHttpResponse response = new OsHttpResponse(); - - if (string.IsNullOrEmpty(request.AddressUrl) - || request.HttpMothed == HttpMothed.None) - { - throw new ArgumentException("对不起,请求出错,请检查参数等设置(地址,请求方式等)!", "request"); - } - HttpWebRequest webrequest = ConfigureWebRequest(request); - - SendBodyDataSync(webrequest, request); - - GetResponse(webrequest, ref response); - - return response; - } - - protected override void AddStaticHeaderDictionary() - { - _notCanAddHeaderDictionary.Add("Accept", (r, v) => r.Accept = v); - _notCanAddHeaderDictionary.Add("Content-Type", (r, v) => r.ContentType = v); - - _notCanAddHeaderDictionary.Add("Date", (r, v) => - { - DateTime parsed; - if (DateTime.TryParse(v, out parsed)) - { - r.Date = parsed; - } - }); - _notCanAddHeaderDictionary.Add("Host", (r, v) => r.Host = v); - _notCanAddHeaderDictionary.Add("Connection", (r, v) => r.Connection = v); - _notCanAddHeaderDictionary.Add("Content-Length", (r, v) => r.ContentLength = Convert.ToInt64(v)); - _notCanAddHeaderDictionary.Add("Expect", (r, v) => r.Expect = v); - _notCanAddHeaderDictionary.Add("If-Modified-Since", (r, v) => r.IfModifiedSince = Convert.ToDateTime(v)); - _notCanAddHeaderDictionary.Add("Referer", (r, v) => r.Referer = v); - _notCanAddHeaderDictionary.Add("Transfer-Encoding", (r, v) => { r.TransferEncoding = v; r.SendChunked = true; }); - _notCanAddHeaderDictionary.Add("User-Agent", (r, v) => r.UserAgent = v); - } - - - - } -} diff --git a/OSS.Http/Enum.cs b/OSS.Http/Enum.cs index a75729d..d21782a 100644 --- a/OSS.Http/Enum.cs +++ b/OSS.Http/Enum.cs @@ -14,22 +14,26 @@ namespace OSS.Http /// /// Get /// - GET = 2, + GET = 10, /// /// post /// - POST = 4, + POST = 20, /// /// PUT /// - PUT=8, + PUT = 30, /// /// DELETE /// - DELETE=16 + DELETE = 40, + HEAD=50, + OPTIONS=60, + TRACE=70 + } /// @@ -54,7 +58,7 @@ namespace OSS.Http /// ErrorButResponse, /// - /// 超市 + /// 超时 /// TimedOut, /// @@ -81,10 +85,10 @@ namespace OSS.Http /// 地址中的值 /// UrlSegment, - /// - /// 头部参数 - /// - Header, + ///// + ///// 头部参数 + ///// + //Header, /// /// cookie /// diff --git a/OSS.Http/HttpUtil.cs b/OSS.Http/HttpUtil.cs index 6bb30d9..629a7c1 100644 --- a/OSS.Http/HttpUtil.cs +++ b/OSS.Http/HttpUtil.cs @@ -1,37 +1,48 @@ using System; +using System.Net.Http; +using System.Threading.Tasks; using OSS.Http.Connect; -using OSS.Http.Interface; using OSS.Http.Models; namespace OSS.Http { /// - /// + /// http请求辅助类 /// public static class HttpUtil { - private static IHttp httpsync = new RestHttp(); + private static HttpClientHandler m_Handler; + private static OsRest m_Client ; + + public static Action SetHandler { get; set; } + /// /// 同步的请求方式 /// /// 请求的参数 /// 自定义的Response结果 - public static OsHttpResponse ExecuteSync(this OsHttpRequest request) + public static Task ExecuteSync(this OsHttpRequest request,HttpCompletionOption completionOption=HttpCompletionOption.ResponseContentRead) { - return httpsync.ExecuteSync(request); + if (m_Client==null) + { + m_Handler=new HttpClientHandler(); + ConfigClientHandler(m_Handler); + m_Client=new OsRest(m_Handler); + } + return m_Client.RestSend(request, completionOption); } - /// - /// 异步的请求方式 + /// 配置请求处理类 /// - /// 请求的参数 - /// - /// 自定义的Response结果 - public static void ExecuteAsync(this OsHttpRequest request, Action callback) + /// + public static void ConfigClientHandler(HttpClientHandler reqHandler) { - httpsync.ExecuteAsync(request, callback); + reqHandler.AllowAutoRedirect = true; + reqHandler.MaxAutomaticRedirections = 5; + reqHandler.UseCookies = true; + SetHandler?.Invoke(reqHandler); } diff --git a/OSS.Http/Interface/IHttp.cs b/OSS.Http/Interface/IHttp.cs deleted file mode 100644 index 5e214b6..0000000 --- a/OSS.Http/Interface/IHttp.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using OSS.Http.Models; - -namespace OSS.Http.Interface -{ - public interface IHttp - { - #region - /// - /// 同步执行 - /// - /// 请求的参数 - /// 自定义的Response结果 - OsHttpResponse ExecuteSync(OsHttpRequest request); - - /// - /// 异步请求 - /// - /// 请求的参数 - /// 自定义的Response结果 - void ExecuteAsync(OsHttpRequest request,Action action); - #endregion - } -} diff --git a/OSS.Http/Models/FileParameter.cs b/OSS.Http/Models/FileParameter.cs index c6237dc..29cb51a 100644 --- a/OSS.Http/Models/FileParameter.cs +++ b/OSS.Http/Models/FileParameter.cs @@ -1,6 +1,5 @@ using System; using System.IO; -using System.Linq; namespace OSS.Http.Models { @@ -29,7 +28,6 @@ namespace OSS.Http.Models }; this.FileName = filename; this.ContentType = contentType; - this.Name = name; } /// diff --git a/OSS.Http/Models/HttpRequest.cs b/OSS.Http/Models/HttpRequest.cs index 7d0e03b..587500d 100644 --- a/OSS.Http/Models/HttpRequest.cs +++ b/OSS.Http/Models/HttpRequest.cs @@ -2,7 +2,8 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; namespace OSS.Http.Models { @@ -17,81 +18,73 @@ namespace OSS.Http.Models FileParameterList = new List(); } - - /// - /// 自定义属性设置 - /// - public Action CustomPropertySetting { get; set; } - - /// - /// form 参数列表 - /// - internal IList FormParameters { get { return GetParameters(ParameterType.Form);} } - /// - /// header 参数列表 - /// - internal IList HeaderParameters { get { return GetParameters(ParameterType.Header); } } - /// - /// Query 参数列表 - /// - internal IList QueryParameters { get { return GetParameters(ParameterType.Query); } } - /// - /// Cookie 参数列表 - /// - internal IList CookieParameters { get { return GetParameters(ParameterType.Cookie); } } - - - - /// - /// 文件参数列表 - /// - public IList FileParameterList { get; set; } /// /// 请求地址信息 /// public string AddressUrl { get; set; } + /// /// 请求方式 /// public HttpMothed HttpMothed { get; set; } + ///// + ///// 是否允许自动重定向 + ///// 默认为true 最大可重定向次数为 5 + ///// + //public bool AllowAutoRedirect { get; set; } = true; + + ///// + ///// 是否使用压缩 + ///// + //public bool AutoDecompres { get; set; } + + ///// + ///// 是否使用cookie + ///// + //public bool UseCookies { get; set; } /// - /// 超时时间(毫秒) + /// 头部属性自定义设置 /// - public int TimeOutMilSeconds { get; set; } + public Action HeaderSetting { get; set; } + + /// + /// HttpClientHandler 自定义属性设置 + /// + public Action HandlerSetting { get; set; } + + #region 请求的内容参数 + + /// + /// 文件参数列表 + /// + public List FileParameterList { get; set; } /// /// 是否存在文件 /// public bool HasFile { - get - { - return FileParameterList.Any(); - } + get { return FileParameterList.Any(); } } + /// - /// 参数列表 + /// 非文件参数列表 /// - public IList Parameters { get; set; } - private IList GetParameters(ParameterType type) - { - return this.Parameters.Where(p => p.Type == type).ToList() ?? new List(); - } + public List Parameters { get; set; } + #endregion /// - /// 自定义内容实体,键值对 key=value&key1=value1 或者自定义内容格式 + /// 自定义内容实体 /// eg:当上传文件时,无法自定义内容 /// public string CustomBody { get; set; } - /// - /// 是否使用压缩 + /// 超时时间(毫秒) /// - public bool IsDecompres { get; set; } - + public int TimeOutMilSeconds { get; set; } } } diff --git a/OSS.Http/Models/HttpResponse.cs b/OSS.Http/Models/HttpResponse.cs deleted file mode 100644 index 7f24cb1..0000000 --- a/OSS.Http/Models/HttpResponse.cs +++ /dev/null @@ -1,116 +0,0 @@ -using OSS.Http.Interface; -using System; -using System.Collections.Generic; -using System.Net; -using System.Text; -using System.Web; - -namespace OSS.Http.Models -{ - /// - /// 响应信息 - /// - public class OsHttpResponse - { - /// - /// 构造函数 - /// - public OsHttpResponse() - { - Headers = new List(); - Cookies = new List(); - } - /// - /// 返回类型 - /// - public string ContentType { get; set; } - - /// - /// 返回内容的长度 - /// - public long ContentLength { get; set; } - - /// - /// 返回内容的编码 - /// - public string ContentEncoding { get; set; } - - private string _content; - /// - /// 返回的内容 - /// - public string Content - { - get - { - if (_content == null && RawBytes != null && RawBytes.Length > 0) - { - Encoding encoding = Encoding.UTF8; - - _content = encoding.GetString(RawBytes); - } - return _content ?? string.Empty; - } - } - - /// - /// 内容的字节流 - /// - public byte[] RawBytes { get; set; } - - /// - /// 返回响应的实际地址 - /// 如果请求过程中出现重定向,此地址 - /// - public Uri ResponseUri { get; set; } - - /// - /// 字符串,包含发送响应的服务器的名称 - /// - public string Server { get; set; } - - /// - /// 返回的Cookie列表 - /// - public IList Cookies { get; private set; } - - private ResponseStatus _responseStatus = ResponseStatus.None; - - /// - /// 返回的状态(请求传输等出现错误等状态) 默认是 None 成功为 Completed - /// - public ResponseStatus ResponseStatus - { - get - { - return _responseStatus; - } - set - { - _responseStatus = value; - } - } - - - /// - /// 返回的 Http状态码 - /// 如: 200, 301等 - /// - public HttpStatusCode StatusCode { get; set; } - /// - /// 返回的状态描述 http状态码的枚举字符串 - /// 如: OK,Moved 等 - /// - public string StatusDescription { get; set; } - - ///// - ///// 错误实体 - ///// - //public Exception ErrorException { get; set; } - - /// - /// 头部列表 - /// - public IList Headers { get; set; } - } -} diff --git a/OSS.Http/Models/Parameter.cs b/OSS.Http/Models/Parameter.cs index 2b422c7..ea0a5c7 100644 --- a/OSS.Http/Models/Parameter.cs +++ b/OSS.Http/Models/Parameter.cs @@ -63,9 +63,6 @@ namespace OSS.Http.Models { return string.Format("{0}={1}", Name.UrlEncode(), Value.UrlEncode()); } - - - } internal static class UrlExtension diff --git a/OSS.Http.ConsoleTest/OSS.Http.ConsoleTest.csproj b/OSS.Http/OSS.Http.NET45.csproj similarity index 63% rename from OSS.Http.ConsoleTest/OSS.Http.ConsoleTest.csproj rename to OSS.Http/OSS.Http.NET45.csproj index 7704774..9d9e635 100644 --- a/OSS.Http.ConsoleTest/OSS.Http.ConsoleTest.csproj +++ b/OSS.Http/OSS.Http.NET45.csproj @@ -4,36 +4,45 @@ Debug AnyCPU - {0504F610-BD59-45B5-988C-BFFE15AAAC82} - Exe + {5A831C5B-8D82-4A6A-A555-3E04847455D1} + Library Properties - OSS.Http.ConsoleTest - OSS.Http.ConsoleTest + OSS.Http + OSS.Http v4.5 512 + - AnyCPU true full false bin\Debug\ - DEBUG;TRACE + TRACE;DEBUG;NET45 prompt 4 + false - AnyCPU pdbonly true bin\Release\ - TRACE + TRACE;NET45 prompt 4 + false + bin\Release\OSS.Http.xml + GlobalizationRules.ruleset + + + + C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Net.Http.dll + + @@ -41,17 +50,16 @@ - + + + + + + - - - - - {5a831c5b-8d82-4a6a-a555-3e04847455d1} - OSS.Http - + + - - - + - - - +