#region Copyright (C) 2016 Kevin (OSS开源系列) 公众号:osscore /*************************************************************************** *   文件功能描述:Http请求 == 主请求实体 * *   创建人: Kevin * 创建人Email:1985088337@qq.com * *****************************************************************************/ #endregion using System; using System.IO; using System.Net.Http; using System.Text; using System.Threading; using System.Threading.Tasks; namespace OSS.Tools.Http { /// /// 请求基类 /// public static class HttpClientExtention { private const string _lineBreak = "\r\n"; /// /// 编码格式 /// public static Encoding Encoding { get; set; } = Encoding.UTF8; #region 扩展方法 /// /// 执行请求方法 /// /// /// /// public static Task SendAsync(this HttpClient client, OssHttpRequest request) { return SendAsync(client, request, HttpCompletionOption.ResponseContentRead, CancellationToken.None); } /// /// 执行请求方法 /// /// /// /// /// public static Task SendAsync(this HttpClient client, OssHttpRequest request, HttpCompletionOption completionOption) { return SendAsync(client, request, completionOption, CancellationToken.None); } /// /// 执行请求方法 /// /// /// /// /// /// public static Task SendAsync(this HttpClient client, OssHttpRequest request, HttpCompletionOption completionOption , CancellationToken cancellationToken) { var reqMsg = new HttpRequestMessage { RequestUri = new Uri(request.address_url), Method = request.http_method }; PackageReqContent(reqMsg, request); // 配置内容 return client.SendAsync(reqMsg, completionOption, cancellationToken); } #endregion #region 配置 ReqMsg信息 /// /// 配置使用的content /// /// /// /// private static void PackageReqContent(HttpRequestMessage reqMsg, OssHttpRequest req) { req.PrepareSend(); if (req.http_method == HttpMethod.Get) { req.RequestSet?.Invoke(reqMsg); return; } if (req.has_file) { var boundary =GetBoundary(); var memory=new MemoryStream(); WriteMultipartFormData(memory, req, boundary); memory.Seek(0, SeekOrigin.Begin);//设置指针到起点 reqMsg.Content = new StreamContent(memory); req.RequestSet?.Invoke(reqMsg); reqMsg.Content.Headers.Remove("Content-Type"); reqMsg.Content.Headers.TryAddWithoutValidation("Content-Type", $"multipart/form-data;boundary={boundary}"); } else { var data = GetNormalFormData(req); reqMsg.Content = new StringContent(data); req.RequestSet?.Invoke(reqMsg); } } #endregion #region 请求数据的 内容 处理 #region 处理带文件上传的数据处理 /// /// 写入 Form 的内容值 【 非文件参数 + 文件头 + 文件参数(内部完成) + 请求结束符 】 /// /// /// /// private static void WriteMultipartFormData(Stream memory, OssHttpRequest request, string boundary) { if (request.form_paras!=null) { foreach (var param in request.form_paras) { WriteStringTo(memory, GetMultipartFormData(param, boundary)); } } foreach (var file in request.file_paras) { //文件头 WriteStringTo(memory, GetMultipartFileHeader(file, boundary)); //文件内容 file.Writer(memory); //文件结尾 WriteStringTo(memory, _lineBreak); } //写入整个请求的底部信息 WriteStringTo(memory, GetMultipartFooter(boundary)); } /// /// 写入 Form 的内容值(文件头) /// /// /// /// private static string GetMultipartFileHeader(FileParameter file, string boundary) { var conType = file.ContentType ?? "application/octet-stream"; return $"--{boundary}{_lineBreak}Content-Disposition: form-data; name=\"{file.Name}\"; filename=\"{file.FileName}\"{_lineBreak}Content-Type: {conType}{_lineBreak}{_lineBreak}"; } /// /// 写入 Form 的内容值(非文件参数) /// /// /// /// private static string GetMultipartFormData(FormParameter param, string boundary) { return $"--{boundary}{_lineBreak}Content-Disposition: form-data; name=\"{param.Name}\"{_lineBreak}{_lineBreak}{param.Value}{_lineBreak}"; } /// /// 写入 Form 的内容值 (请求结束符) /// /// /// private static string GetMultipartFooter(string boundary) { return $"--{boundary}--{_lineBreak}"; } #endregion #region 不包含文件的数据处理(正常 get/post 请求) /// /// 写入请求的内容信息 (非文件上传请求) /// /// /// private static string GetNormalFormData(OssHttpRequest request) { var formstring = new StringBuilder(); if (request.form_paras!=null) { foreach (var p in request.form_paras) { if (formstring.Length > 1) formstring.Append("&"); formstring.AppendFormat(p.ToString()); } } if (string.IsNullOrEmpty(request.custom_body)) return formstring.ToString(); if (formstring.Length > 1) formstring.Append("&"); formstring.Append(request.custom_body); return formstring.ToString(); } #endregion #endregion #region 请求辅助方法 /// /// 写入数据方法(将数据写入 webrequest) /// /// /// /// 写入的字节数量 private static void WriteStringTo(Stream stream, string toWrite) { var bytes = Encoding.GetBytes(toWrite); stream.Write(bytes, 0, bytes.Length); } /// /// 创建 请求 分割界限 /// /// private static string GetBoundary() { const string pattern = "abcdefghijklmnopqrstuvwxyz0123456789"; var boundaryBuilder = new StringBuilder(); var rnd = new Random(); for (var i = 0; i < 10; i++) { var index = rnd.Next(pattern.Length); boundaryBuilder.Append(pattern[index]); } return $"-------{boundaryBuilder}"; } #endregion } }