using System.Collections.Specialized; using System.Net.Http.Headers; using System.Text; using DS.Module.Core.Extensions; using Newtonsoft.Json; namespace DS.Module.Core { /// /// 提供对HTTP请求的低级别访问 /// public class ApiFox : IDisposable { readonly HttpClient http; /// /// 基URI /// public Uri? BaseUri { get { return http.BaseAddress; } set { http.BaseAddress = value; } } /// /// 默认请求头 /// public HttpRequestHeaders DefaultHeaders => http.DefaultRequestHeaders; /// /// 在发送网络请求之前的事件 /// public event EventHandler? BeforeSend; /// /// 在发送网络请求完成时的事件 /// public event EventHandler? Completed; /// /// 初始化 /// /// 连接池使用时间,默认为30分钟 public ApiFox(int pooledMinutes = 30) { var handler = new SocketsHttpHandler { PooledConnectionLifetime = TimeSpan.FromMinutes(pooledMinutes) }; http = new(handler); http.DefaultRequestHeaders.Add("User-Agent", $"X-{nameof(ApiFox)}"); http.DefaultRequestHeaders.Add("Accept", "application/json, text/plain"); } /// /// 发起请求 /// /// 请求结果的类型 /// 请求Url /// 查询字符串的键值对 /// /// 为null或空字符串 public async Task> GetAsync(string url, NameValueCollection? keyValues = null) { string queryString = string.Empty; if (keyValues != null && keyValues.Count > 0) { StringBuilder sb = new StringBuilder(); foreach (string key in keyValues.Keys) { var values = keyValues.GetValues(key); if (values?.Length > 0) { for (int i = 0; i < values.Length; i++) { sb.Append($"&{key}={values[i]}"); } } } if (sb.Length > 0) //移除首个&符 sb.Remove(0, 1); queryString = sb.ToString(); } if (!queryString.IsNullOrEmpty()) url = url.LastOrDefault() == '?' ? url + queryString : url + "?" + queryString; var response = await SendRequestAsync(HttpMethod.Get, url); T? data = default; if (response != null && response.IsSuccessStatusCode) { string json = await response.Content.ReadAsStringAsync(); data = JsonConvert.DeserializeObject(json); return DataResult.Success(data); } return DataResult.Failed(response.ReasonPhrase); } /// /// 发起请求 /// /// 请求结果的类型 /// 请求Url /// 请求参数对象 /// /// 为null或空字符串 public async Task> PostAsync(string url, object? requestParams = null) { var response = await SendRequestAsync(HttpMethod.Post, url, requestParams); T? data = default; if (response != null && response.IsSuccessStatusCode) { string json = await response.Content.ReadAsStringAsync(); data = JsonConvert.DeserializeObject(json); return DataResult.Success(data); } return DataResult.Failed(response.ReasonPhrase); } /// /// 发起HTTP请求 /// /// 请求方法 /// 请求Url /// 请求参数 /// /// 为null /// 为null或空字符串 /// 不等于 GET/POST/PUT/Delete 中的任何一个请求方法 public async Task SendRequestAsync(HttpMethod method, string url, object? requestParams = null) { ArgumentNullException.ThrowIfNull(method); ArgumentException.ThrowIfNullOrEmpty(url); Uri? reqUri = default; if (BaseUri == null) { if (!Uri.TryCreate(url, UriKind.RelativeOrAbsolute, out Uri? uri)) throw new ArgumentException("给定的URL格式无效", nameof(url)); reqUri = new Uri(url); } else { reqUri = new(BaseUri, url); } OnBeforeSend(new BeforeSendEventArgs { RequestHeaders = http.DefaultRequestHeaders, RequestParameter = requestParams, RequestUri = reqUri }); HttpResponseMessage? response = null; if (method == HttpMethod.Get) { response = await http.GetAsync(reqUri); } else if (method == HttpMethod.Post) { string json = JsonConvert.SerializeObject(requestParams); var jsonRequest = new StringContent(json, Encoding.UTF8, "application/json"); response = await http.PostAsync(reqUri, jsonRequest); } else if (method == HttpMethod.Put) { string json = JsonConvert.SerializeObject(requestParams); var jsonRequest = new StringContent(json, Encoding.UTF8, "application/json"); response = await http.PutAsync(reqUri, jsonRequest); } else if (method == HttpMethod.Delete) { response = await http.DeleteAsync(reqUri); } else { throw new NotSupportedException($"不支持的请求方法:{method.Method}"); } OnCompleted(new CompleteEventArgs { RequestUri = reqUri, Response = response }); return response; } /// /// 在发送网络请求之前调用 /// /// 事件参数 protected virtual void OnBeforeSend(BeforeSendEventArgs e) { BeforeSend?.Invoke(this, e); } /// /// 在发送网络请求完成时调用 /// /// 事件参数 protected virtual void OnCompleted(CompleteEventArgs e) { Completed?.Invoke(this, e); } /// /// 释放网络连接 /// public void Dispose() => http?.Dispose(); } /// /// 发送网络请求之前的事件参数 /// public class BeforeSendEventArgs : EventArgs { /// /// 远程请求的URI /// public Uri RequestUri { get; internal set; } /// /// 请求标头 /// public HttpRequestHeaders RequestHeaders { get; internal set; } /// /// 请求参数 /// public object? RequestParameter { get; set; } } /// /// 发送网络请求完成的事件参数 /// public class CompleteEventArgs : EventArgs { /// /// 远程请求的URI /// public Uri RequestUri { get; internal set; } /// /// 网络响应对象 /// public HttpResponseMessage Response { get; internal set; } } }