From 148f51967eb0d37469ff23d6bde8d94e2554a94c Mon Sep 17 00:00:00 2001 From: oneRain Date: Fri, 9 Aug 2019 14:32:28 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20=E5=88=A0=E9=99=A4=20HttpClient?= =?UTF-8?q?=EF=BC=8C=E4=BD=BF=E7=94=A8=20.Net=20=E6=A0=87=E5=87=86?= =?UTF-8?q?=E5=BA=93=E4=B8=AD=E7=9A=84=20HttpClient?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Storage/Storage/Internal/AVCorePlugins.cs | 16 ---- .../Internal/AppRouter/AppRouterController.cs | 25 +++--- .../Internal/Command/AVCommandRunner.cs | 14 +-- .../File/Controller/AVFileController.cs | 49 ++--------- .../File/Controller/AWSS3FileController.cs | 17 ++-- .../Controller/QCloudCosFileController.cs | 25 ++++-- .../File/Controller/QiniuFileController.cs | 56 ++++++++---- .../Storage/Internal/HttpClient/HttpClient.cs | 86 ------------------- .../Internal/HttpClient/HttpRequest.cs | 22 ----- 9 files changed, 93 insertions(+), 217 deletions(-) delete mode 100644 Storage/Storage/Internal/HttpClient/HttpClient.cs delete mode 100644 Storage/Storage/Internal/HttpClient/HttpRequest.cs diff --git a/Storage/Storage/Internal/AVCorePlugins.cs b/Storage/Storage/Internal/AVCorePlugins.cs index 9e65d8c..c0dcc06 100644 --- a/Storage/Storage/Internal/AVCorePlugins.cs +++ b/Storage/Storage/Internal/AVCorePlugins.cs @@ -16,7 +16,6 @@ namespace LeanCloud.Storage.Internal { #region Server Controllers - private HttpClient httpClient; private AppRouterController appRouterController; private AVCommandRunner commandRunner; private StorageController storageController; @@ -40,7 +39,6 @@ namespace LeanCloud.Storage.Internal { public void Reset() { lock (mutex) { - HttpClient = null; AppRouterController = null; CommandRunner = null; StorageController = null; @@ -57,20 +55,6 @@ namespace LeanCloud.Storage.Internal { } } - public HttpClient HttpClient { - get { - lock (mutex) { - httpClient = httpClient ?? new HttpClient(); - return httpClient; - } - } - set { - lock (mutex) { - httpClient = value; - } - } - } - public AppRouterController AppRouterController { get { lock (mutex) { diff --git a/Storage/Storage/Internal/AppRouter/AppRouterController.cs b/Storage/Storage/Internal/AppRouter/AppRouterController.cs index 3ff229d..0f48f10 100644 --- a/Storage/Storage/Internal/AppRouter/AppRouterController.cs +++ b/Storage/Storage/Internal/AppRouter/AppRouterController.cs @@ -36,18 +36,23 @@ namespace LeanCloud.Storage.Internal { string appId = AVClient.CurrentConfiguration.ApplicationId; string url = string.Format("https://app-router.leancloud.cn/2/route?appId={0}", appId); - var request = new HttpRequest { - Uri = new Uri(url), - Method = HttpMethod.Get, - Headers = null, - Data = null + HttpClient client = new HttpClient(); + HttpRequestMessage request = new HttpRequestMessage { + RequestUri = new Uri(url), + Method = HttpMethod.Get }; - var ret = await AVPlugins.Instance.HttpClient.ExecuteAsync(request, null, null, CancellationToken.None); - if (ret.Item1 != HttpStatusCode.OK) { - throw new AVException(AVException.ErrorCode.ConnectionFailed, "can not reach router.", null); - } + try { + HttpResponseMessage response = await client.SendAsync(request); + client.Dispose(); + request.Dispose(); - return await JsonUtils.DeserializeObjectAsync(ret.Item2); + string content = await response.Content.ReadAsStringAsync(); + response.Dispose(); + + return await JsonUtils.DeserializeObjectAsync(content); + } catch (Exception e) { + throw new AVException(AVException.ErrorCode.ConnectionFailed, "can not reach router.", e); + } } public void Clear() { diff --git a/Storage/Storage/Internal/Command/AVCommandRunner.cs b/Storage/Storage/Internal/Command/AVCommandRunner.cs index 5c8d37e..0a8585a 100644 --- a/Storage/Storage/Internal/Command/AVCommandRunner.cs +++ b/Storage/Storage/Internal/Command/AVCommandRunner.cs @@ -18,10 +18,10 @@ namespace LeanCloud.Storage.Internal { const string USE_PRODUCTION = "1"; const string USE_DEVELOPMENT = "0"; - private readonly System.Net.Http.HttpClient httpClient; + private readonly HttpClient httpClient; public AVCommandRunner() { - httpClient = new System.Net.Http.HttpClient(); + httpClient = new HttpClient(); ProductHeaderValue product = new ProductHeaderValue(AVClient.Name, AVClient.Version); httpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue(product)); httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(APPLICATION_JSON)); @@ -48,15 +48,9 @@ namespace LeanCloud.Storage.Internal { /// /// /// - /// - /// /// /// - public async Task> RunCommandAsync(AVCommand command, - IProgress uploadProgress = null, - IProgress downloadProgress = null, - CancellationToken cancellationToken = default) { - + public async Task> RunCommandAsync(AVCommand command,CancellationToken cancellationToken = default) { string content = JsonConvert.SerializeObject(command.Content); var request = new HttpRequestMessage { RequestUri = command.Uri, @@ -115,7 +109,7 @@ namespace LeanCloud.Storage.Internal { return new Tuple(responseCode, default); } - static void PrintRequest(System.Net.Http.HttpClient client, HttpRequestMessage request, string content) { + static void PrintRequest(HttpClient client, HttpRequestMessage request, string content) { StringBuilder sb = new StringBuilder(); sb.AppendLine("=== HTTP Request Start ==="); sb.AppendLine($"URL: {request.RequestUri}"); diff --git a/Storage/Storage/Internal/File/Controller/AVFileController.cs b/Storage/Storage/Internal/File/Controller/AVFileController.cs index 735fe40..f58a30e 100644 --- a/Storage/Storage/Internal/File/Controller/AVFileController.cs +++ b/Storage/Storage/Internal/File/Controller/AVFileController.cs @@ -6,53 +6,15 @@ using System.Net; using System.Net.Http; using System.Collections.Generic; using System.Linq; -using Newtonsoft.Json; namespace LeanCloud.Storage.Internal { - /// - /// AVF ile controller. - /// - public class AVFileController { - /// - /// Saves the async. - /// - /// The async. - /// State. - /// Data stream. - /// Session token. - /// Progress. - /// Cancellation token. - public virtual async Task SaveAsync(FileState state, + public abstract class AVFileController { + public abstract Task SaveAsync(FileState state, Stream dataStream, String sessionToken, IProgress progress, - CancellationToken cancellationToken = default(CancellationToken)) { - if (state.Url != null) { - // !isDirty - return state; - } + CancellationToken cancellationToken = default(CancellationToken)); - if (cancellationToken.IsCancellationRequested) { - return null; - } - - var oldPosition = dataStream.Position; - - var request = new HttpRequest { - Uri = new Uri("files/" + state.Name), - Method = HttpMethod.Post, - Headers = new List> { - new KeyValuePair("Content-Type", state.MimeType) - } - }; - var ret = await AVPlugins.Instance.HttpClient.ExecuteAsync(request, null, null, CancellationToken.None); - var jsonData = JsonConvert.DeserializeObject>(ret.Item2, new LeanCloudJsonConverter()); - return new FileState { - Name = jsonData["name"] as string, - Url = new Uri(jsonData["url"] as string, UriKind.Absolute), - MimeType = state.MimeType - }; - } public Task DeleteAsync(FileState state, string sessionToken, CancellationToken cancellationToken) { var command = new AVCommand { Path = $"files/{state.ObjectId}", @@ -60,6 +22,7 @@ namespace LeanCloud.Storage.Internal { }; return AVPlugins.Instance.CommandRunner.RunCommandAsync>(command, cancellationToken: cancellationToken); } + internal Task>> GetFileToken(FileState fileState, CancellationToken cancellationToken) { Task>> rtn; string currentSessionToken = AVUser.CurrentSessionToken; @@ -78,6 +41,7 @@ namespace LeanCloud.Storage.Internal { }; return AVPlugins.Instance.CommandRunner.RunCommandAsync>(command); } + public Task GetAsync(string objectId, string sessionToken, CancellationToken cancellationToken) { var command = new AVCommand { Path = $"files/{objectId}", @@ -94,6 +58,7 @@ namespace LeanCloud.Storage.Internal { }; }); } + internal static string GetUniqueName(FileState fileState) { string key = Random(12); string extension = Path.GetExtension(fileState.Name); @@ -101,12 +66,14 @@ namespace LeanCloud.Storage.Internal { fileState.CloudName = key; return key; } + internal static string Random(int length) { const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz"; var random = new Random(); return new string(Enumerable.Repeat(chars, length) .Select(s => s[random.Next(s.Length)]).ToArray()); } + internal static double CalcProgress(double already, double total) { var pv = (1.0 * already / total); return Math.Round(pv, 3); diff --git a/Storage/Storage/Internal/File/Controller/AWSS3FileController.cs b/Storage/Storage/Internal/File/Controller/AWSS3FileController.cs index 5ad00f6..2dfa8bb 100644 --- a/Storage/Storage/Internal/File/Controller/AWSS3FileController.cs +++ b/Storage/Storage/Internal/File/Controller/AWSS3FileController.cs @@ -2,7 +2,6 @@ using System.Threading.Tasks; using System.Threading; using System.IO; -using LeanCloud.Storage.Internal; using System.Collections.Generic; using System.Net.Http; @@ -29,13 +28,19 @@ namespace LeanCloud.Storage.Internal { internal async Task PutFile(FileState state, string uploadUrl, Stream dataStream) { IList> makeBlockHeaders = new List>(); makeBlockHeaders.Add(new KeyValuePair("Content-Type", state.MimeType)); - var request = new HttpRequest { - Uri = new Uri(uploadUrl), + + HttpClient client = new HttpClient(); + HttpRequestMessage request = new HttpRequestMessage { + RequestUri = new Uri(uploadUrl), Method = HttpMethod.Put, - Headers = makeBlockHeaders, - Data = dataStream + Content = new StreamContent(dataStream) }; - await AVPlugins.Instance.HttpClient.ExecuteAsync(request, null, null, CancellationToken.None); + foreach (var header in makeBlockHeaders) { + request.Headers.Add(header.Key, header.Value); + } + await client.SendAsync(request); + client.Dispose(); + request.Dispose(); return state; } } diff --git a/Storage/Storage/Internal/File/Controller/QCloudCosFileController.cs b/Storage/Storage/Internal/File/Controller/QCloudCosFileController.cs index 30b4037..be6f47f 100644 --- a/Storage/Storage/Internal/File/Controller/QCloudCosFileController.cs +++ b/Storage/Storage/Internal/File/Controller/QCloudCosFileController.cs @@ -20,7 +20,7 @@ namespace LeanCloud.Storage.Internal { bool done; private long sliceSize = (long)CommonSize.KB512; - public Task SaveAsync(FileState state, + public override Task SaveAsync(FileState state, Stream dataStream, string sessionToken, IProgress progress, @@ -132,6 +132,7 @@ namespace LeanCloud.Storage.Internal { return HexStringFromBytes(hashBytes); } + async Task>> PostToQCloud( Dictionary body, byte[] sliceFile, @@ -146,16 +147,22 @@ namespace LeanCloud.Storage.Internal { sliceHeaders.Add(new KeyValuePair("Content-Type", contentType)); - var request = new HttpRequest { - Uri = new Uri(this.uploadUrl), + var client = new HttpClient(); + var request = new HttpRequestMessage { + RequestUri = new Uri(uploadUrl), Method = HttpMethod.Post, - Headers = sliceHeaders, - Data = tempStream + Content = new StreamContent(tempStream) }; - var ret = await AVPlugins.Instance.HttpClient.ExecuteAsync(request, null, null, CancellationToken.None); - var result = new Tuple>(ret.Item1, - JsonConvert.DeserializeObject>(ret.Item2, new LeanCloudJsonConverter())); - return result; + foreach (var header in sliceHeaders) { + request.Headers.Add(header.Key, header.Value); + } + var response = await client.SendAsync(request); + client.Dispose(); + request.Dispose(); + var content = await response.Content.ReadAsStringAsync(); + response.Dispose(); + // TODO 修改反序列化返回 + return await JsonUtils.DeserializeObjectAsync>>(content); } public static Stream HttpUploadFile(byte[] file, string fileName, out string contentType, out long contentLength, IDictionary nvc) { string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x"); diff --git a/Storage/Storage/Internal/File/Controller/QiniuFileController.cs b/Storage/Storage/Internal/File/Controller/QiniuFileController.cs index 5dd8269..935f1ae 100644 --- a/Storage/Storage/Internal/File/Controller/QiniuFileController.cs +++ b/Storage/Storage/Internal/File/Controller/QiniuFileController.cs @@ -175,25 +175,41 @@ namespace LeanCloud.Storage.Internal MemoryStream firstChunkData = new MemoryStream(firstChunkBinary, 0, firstChunkBinary.Length); var headers = GetQiniuRequestHeaders(state); headers.Add(new KeyValuePair("Content-Type", "application/octet-stream")); - var request = new HttpRequest { - Uri = new Uri(new Uri(UP_HOST) + string.Format("mkblk/{0}", blcokSize)), + var client = new HttpClient(); + var request = new HttpRequestMessage { + RequestUri = new Uri($"{UP_HOST}/mkblk/{blcokSize}"), Method = HttpMethod.Post, - Headers = headers, - Data = firstChunkData + Content = new StreamContent(firstChunkData) }; - return await AVPlugins.Instance.HttpClient.ExecuteAsync(request, null, null, CancellationToken.None); + foreach (var header in headers) { + request.Headers.Add(header.Key, header.Value); + } + var response = await client.SendAsync(request); + client.Dispose(); + request.Dispose(); + var content = await response.Content.ReadAsStringAsync(); + response.Dispose(); + return await JsonUtils.DeserializeObjectAsync>(content); } async Task> PutChunk(FileState state, byte[] chunkBinary, string LastChunkctx, long currentChunkOffsetInBlock) { MemoryStream chunkData = new MemoryStream(chunkBinary, 0, chunkBinary.Length); - var request = new HttpRequest { - Uri = new Uri(new Uri(UP_HOST) + string.Format("bput/{0}/{1}", LastChunkctx, currentChunkOffsetInBlock)), + var client = new HttpClient(); + var request = new HttpRequestMessage { + RequestUri = new Uri($"{UP_HOST}/bput/{LastChunkctx}/{currentChunkOffsetInBlock}"), Method = HttpMethod.Post, - Headers = GetQiniuRequestHeaders(state), - Data = chunkData + Content = new StreamContent(chunkData) }; - var ret = await AVPlugins.Instance.HttpClient.ExecuteAsync(request, null, null, CancellationToken.None); - return ret; + var headers = GetQiniuRequestHeaders(state); + foreach (var header in headers) { + request.Headers.Add(header.Key, header.Value); + } + var response = await client.SendAsync(request); + client.Dispose(); + request.Dispose(); + var content = await response.Content.ReadAsStringAsync(); + response.Dispose(); + return await JsonUtils.DeserializeObjectAsync>(content); } internal async Task> QiniuMakeFile(FileState state, Stream dataStream, string upToken, string key, long fsize, string[] ctxes, CancellationToken cancellationToken) @@ -232,15 +248,21 @@ namespace LeanCloud.Storage.Internal } } body.Seek(0, SeekOrigin.Begin); - var request = new HttpRequest { - Uri = new Uri(urlBuilder.ToString()), + + var client = new HttpClient(); + var request = new HttpRequestMessage { + RequestUri = new Uri(urlBuilder.ToString()), Method = HttpMethod.Post, - Headers = headers, - Data = body + Content = new StreamContent(body) }; - var ret = await AVPlugins.Instance.HttpClient.ExecuteAsync(request, null, null, CancellationToken.None); - return ret; + var response = await client.SendAsync(request); + client.Dispose(); + request.Dispose(); + var content = await response.Content.ReadAsStringAsync(); + response.Dispose(); + return await JsonUtils.DeserializeObjectAsync>(content); } + internal void MergeFromJSON(FileState state, IDictionary jsonData) { lock (this.mutex) diff --git a/Storage/Storage/Internal/HttpClient/HttpClient.cs b/Storage/Storage/Internal/HttpClient/HttpClient.cs deleted file mode 100644 index b545737..0000000 --- a/Storage/Storage/Internal/HttpClient/HttpClient.cs +++ /dev/null @@ -1,86 +0,0 @@ -using System; -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using System.Text; -using System.IO; -using NetHttpClient = System.Net.Http.HttpClient; - -namespace LeanCloud.Storage.Internal { - public class HttpClient { - static readonly HashSet HttpContentHeaders = new HashSet { - { "Allow" }, - { "Content-Disposition" }, - { "Content-Encoding" }, - { "Content-Language" }, - { "Content-Length" }, - { "Content-Location" }, - { "Content-MD5" }, - { "Content-Range" }, - { "Content-Type" }, - { "Expires" }, - { "Last-Modified" } - }; - - readonly NetHttpClient client; - - public HttpClient() { - client = new NetHttpClient(); - // 设置版本号 - client.DefaultRequestHeaders.Add("User-Agent", $"LeanCloud-csharp-sdk-{AVClient.Version}"); - } - - public HttpClient(NetHttpClient client) { - this.client = client; - } - - public async Task> ExecuteAsync(HttpRequest httpRequest, - IProgress uploadProgress, - IProgress downloadProgress, - CancellationToken cancellationToken) { - - HttpMethod httpMethod = httpRequest.Method; - HttpRequestMessage message = new HttpRequestMessage(httpMethod, httpRequest.Uri); - - // Fill in zero-length data if method is post. - if (httpRequest.Data == null && httpRequest.Method == HttpMethod.Post) { - message.Content = new StreamContent(new MemoryStream(new byte[0])); - } - - if (httpRequest.Data != null) { - message.Content = new StreamContent(httpRequest.Data); - } - - if (httpRequest.Headers != null) { - foreach (var header in httpRequest.Headers) { - if (!string.IsNullOrEmpty(header.Value)) { - if (HttpContentHeaders.Contains(header.Key)) { - message.Content.Headers.Add(header.Key, header.Value); - } else { - message.Headers.Add(header.Key, header.Value); - } - } - } - } - - // Avoid aggressive caching on Windows Phone 8.1. - message.Headers.Add("Cache-Control", "no-cache"); - message.Headers.IfModifiedSince = DateTimeOffset.UtcNow; - - uploadProgress?.Report(new AVUploadProgressEventArgs { Progress = 0 }); - var response = await client.SendAsync(message, HttpCompletionOption.ResponseHeadersRead, cancellationToken); - uploadProgress?.Report(new AVUploadProgressEventArgs { Progress = 1 }); - message.Dispose(); - - var resultString = await response.Content.ReadAsStringAsync(); - response.Dispose(); - - downloadProgress?.Report(new AVDownloadProgressEventArgs { Progress = 1 }); - - return new Tuple(response.StatusCode, resultString); - } - } -} diff --git a/Storage/Storage/Internal/HttpClient/HttpRequest.cs b/Storage/Storage/Internal/HttpClient/HttpRequest.cs deleted file mode 100644 index c1a5720..0000000 --- a/Storage/Storage/Internal/HttpClient/HttpRequest.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Net.Http; - -namespace LeanCloud.Storage.Internal -{ - /// - /// IHttpRequest is an interface that provides an API to execute HTTP request data. - /// - public class HttpRequest - { - public Uri Uri { get; set; } - - public IList> Headers { get; set; } - - // HttpMethod - public HttpMethod Method { get; set; } - - public virtual Stream Data { get; set; } - } -}