/// <summary> /// 异步获取响应字节集合。 /// </summary> /// <param name="uri">给定的 <see cref="Uri"/>。</param> /// <param name="postData">给定要提交的数据(可选)。</param> /// <param name="enableCodec">启用字节编解码传输(可选)。</param> /// <param name="parameters">给定的自定义参数(可选)。</param> /// <param name="cancellationToken">给定的 <see cref="CancellationToken"/>(可选)。</param> /// <returns>返回一个包含字节数组的异步操作。</returns> public virtual async Task <byte[]> GetResponseBytesAsync(Uri uri, string postData = null, bool enableCodec = false, RequestParameters parameters = default, CancellationToken cancellationToken = default) { var stream = await GetResponseStreamAsync(uri, postData, enableCodec, parameters, cancellationToken).ConfigureAwait(); if (stream.IsNotNull()) { var bytes = Array.Empty <byte>(); using (var ms = new MemoryStream()) { var buffer = new byte[64 * Options.BufferSize]; int length; while ((length = stream.Read(buffer, 0, buffer.Length)) > 0) { ms.Write(buffer, 0, length); } bytes = ms.ToArray(); } return(ByteCodec.Decode(bytes, enableCodec)); } return(null); }
/// <summary> /// 异步获取响应字节数组。 /// </summary> /// <param name="uri">给定的 <see cref="Uri"/>。</param> /// <param name="postData">给定要提交的数据(可选)。</param> /// <param name="enableCodec">启用字节编解码传输(可选)。</param> /// <param name="parameters">给定的自定义参数(可选)。</param> /// <param name="cancellationToken">给定的 <see cref="CancellationToken"/>(可选)。</param> /// <returns>返回一个包含字节数组的异步操作。</returns> public override async Task <byte[]> GetResponseBytesAsync(Uri uri, string postData = null, bool enableCodec = false, RequestParameters parameters = default, CancellationToken cancellationToken = default) { var message = await GetResponseMessage(uri, postData, enableCodec, parameters, cancellationToken).ConfigureAwait(); var buffer = await message.Content.ReadAsByteArrayAsync().ConfigureAwait(); if (buffer.IsNotEmpty()) { return(ByteCodec.Decode(buffer, enableCodec)); } return(buffer); }
/// <summary> /// 异步获取响应流。 /// </summary> /// <param name="uri">给定的 <see cref="Uri"/>。</param> /// <param name="postData">给定要提交的数据(可选)。</param> /// <param name="enableCodec">启用字节编解码传输(可选)。</param> /// <param name="parameters">给定的自定义参数(可选)。</param> /// <param name="cancellationToken">给定的 <see cref="CancellationToken"/>(可选)。</param> /// <returns>返回一个包含 <see cref="Stream"/> 的异步操作。</returns> public override Task <Stream> GetResponseStreamAsync(Uri uri, string postData = null, bool enableCodec = false, RequestParameters parameters = default, CancellationToken cancellationToken = default) { uri.NotNull(nameof(uri)); HttpWebRequest request; return(cancellationToken.RunOrCancelAsync(() => { var opts = Options.Requester; request = WebRequest.CreateHttp(uri); request.Timeout = (int)opts.Timeout.TotalMilliseconds; request.UserAgent = opts.UserAgent; if (parameters.Accept.IsNotEmpty()) { request.Accept = parameters.Accept; } if (parameters.ContentType.IsNotEmpty()) { request.ContentType = parameters.ContentType; } if (parameters.Headers.IsNotEmpty()) { parameters.Headers.ForEach(pair => { request.Headers.Add(pair.Key, pair.Value); }); } if (postData.IsNotEmpty()) { request.ContentType = $"application/x-www-form-urlencoded; charset={Encoding.AsName()}"; request.Method = "POST"; } return Policy .Handle <IOException>(exception => { Logger.LogError(exception, exception.AsInnerMessage()); return true; }) .OrResult <Stream>(r => r.IsNull()) .WaitAndRetry(opts.RetryCount, opts.SleepDurationFactory, (exception, sleepDuration, retryCount, context) => { Logger.LogDebug($"Retry {retryCount} times from {sleepDuration.TotalMilliseconds} milliseconds later"); }) .Execute(GetResponseStream); })); Stream GetResponseStream() { if (postData.IsNotEmpty()) { var buffer = ByteCodec.EncodeStringAsBytes(postData, enableCodec); request.ContentLength = buffer.Length; var stream = request.GetRequestStream(); stream.Write(buffer, 0, buffer.Length); Logger.LogDebug($"Send data: {postData}"); Logger.LogDebug($"Enable codec: {enableCodec}"); } return(request.GetResponse().GetResponseStream()); } }
protected virtual Task <HttpResponseMessage> GetResponseMessage(Uri uri, string postData = null, bool enableCodec = false, RequestParameters parameters = default, CancellationToken cancellationToken = default) { var opts = Options.Requester; var client = Factory.CreateClient(); client.Timeout = opts.Timeout; client.DefaultRequestHeaders.Add("User-Agent", opts.UserAgent); if (parameters.Accept.IsNotEmpty()) { client.DefaultRequestHeaders.Add("Accept", parameters.Accept); } if (parameters.ContentType.IsNotEmpty()) { client.DefaultRequestHeaders.Add("Content-Type", parameters.ContentType); } if (parameters.Headers.IsNotEmpty()) { parameters.Headers.ForEach(pair => { client.DefaultRequestHeaders.Add(pair.Key, pair.Value); }); } return(Policy .Handle <HttpRequestException>(exception => { Logger.LogError(exception, exception.AsInnerMessage()); return true; }) .OrResult <HttpResponseMessage>(result => { Logger.LogTrace(result.StatusCode.ToString()); return result.StatusCode == HttpStatusCode.BadGateway; }) .WaitAndRetryAsync(opts.RetryCount, opts.SleepDurationFactory, (exception, sleepDuration, retryCount, context) => { Logger.LogDebug($"Retry {retryCount} times from {sleepDuration.TotalMilliseconds} milliseconds later"); }) .ExecuteAsync(GetResponseMessageAsync)); async Task <HttpResponseMessage> GetResponseMessageAsync() { HttpResponseMessage responseMessage; if (postData.IsNotEmpty()) { var buffer = ByteCodec.EncodeStringAsBytes(postData, enableCodec); var content = new ByteArrayContent(buffer); responseMessage = await client.PostAsync(uri, content, cancellationToken).ConfigureAwait(); Logger.LogDebug($"Send data: {postData}"); Logger.LogDebug($"Enable codec: {enableCodec}"); } else { responseMessage = await client.GetAsync(uri, cancellationToken).ConfigureAwait(); } return(responseMessage); } }