using Binance.TradeRobot.Common.Extensions; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Text; namespace Binance.TradeRobot.Common.Http { public class RestApiService { public const string ContentType_Json = "application/json"; public const string ContentType_Form = "application/x-www-form-urlencoded"; public TimeSpan TimeOut { get; set; } = new TimeSpan(0, 0, 20); private IHttpClientFactory httpClientFactory; public RestApiService(IHttpClientFactory httpClientFactory) { this.httpClientFactory = httpClientFactory; } /// /// 发送请求 /// /// /// /// /// /// /// /// /// /// /// /// /// public RestApiResult SendRequest(string apiHost, string apiPath, object param, IDictionary requestHeaders, HttpMethod httpMethod, string contentType = ContentType_Json, ParamPosition paramPosition = ParamPosition.Body, bool useRandomTimeStamp = false, bool getResponseHeader = false, HttpCompletionOption httpCompletionOption = HttpCompletionOption.ResponseContentRead, string httpClientName = "") { //Get和Delete强制使用QueryString形式传参 if (httpMethod == HttpMethod.Get || httpMethod == HttpMethod.Delete) paramPosition = ParamPosition.Query; //拼接Url var url = string.IsNullOrEmpty(apiPath) ? apiHost : $"{apiHost.TrimEnd('/')}/{apiPath.TrimStart('/')}"; var isCombineParam = false; if (paramPosition == ParamPosition.Query && param != null) { url = $"{url}{(param.ToString().StartsWith("?") ? string.Empty : "?")}{param}"; isCombineParam = true; } //使用时间戳绕过CDN if (useRandomTimeStamp) url = $"{url}{(isCombineParam ? "&" : "?")}t={DateTime.Now.ToFileTime()}"; using (var httpClient = httpClientFactory.CreateClient()) { httpClient.Timeout = TimeOut; using (var request = new HttpRequestMessage(httpMethod, url)) { if (requestHeaders != null && requestHeaders.Count > 0) foreach (var key in requestHeaders.Keys) request.Headers.Add(key, requestHeaders[key]); if (paramPosition == ParamPosition.Body && param != null) request.Content = new StringContent(contentType == ContentType_Json ? JsonConvert.SerializeObject(param) : param.ToString(), Encoding.UTF8, contentType); using (var response = httpClient.SendAsync(request, httpCompletionOption).Result) { if (!response.IsSuccessStatusCode && response.StatusCode != HttpStatusCode.Redirect && response.StatusCode != HttpStatusCode.Moved) throw new Exception($"Reuqest {url} HttpCode {response.StatusCode}"); return new RestApiResult() { StatusCode = response.StatusCode, Content = httpCompletionOption == HttpCompletionOption.ResponseContentRead ? response.Content.ReadAsStringAsync().Result : string.Empty, Headers = getResponseHeader ? response.Headers : null }; } } } } } public class RestApiResult { public HttpStatusCode StatusCode { get; set; } public string Content { get; set; } public HttpResponseHeaders Headers { get; set; } } /// /// 参数传递位置 /// public enum ParamPosition { Query, Body } }