多线程环境下HttpClient SendAsync结合ZipArchive报错排查
并发请求下Token缓存与HTTP压缩错误问题
场景描述
从外部API调用自研API,同时发起6次请求,需求是首次请求获取AccessToken并缓存复用:
- 先同步发起第一个请求,再异步发起其余5个,执行正常;
- 同时发起6个请求时,
SendAsync抛出错误:"The archive entry was compressed using an unsupported compression method"; - 移除代码中的
SemaphoreSlim,让每个请求独立生成Token(无法复用缓存),请求可正常执行。
Token缓存类代码
public class AzureCredentialCached : ChainedTokenCredential { private static readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); public override async ValueTask<AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken = default) { AccessToken? cachedToken = _cacheService.TryGetToken(requestContext, _uri); if (cachedToken is null) { await _semaphore.WaitAsync(cancellationToken); try { cachedToken = _cacheService.TryGetToken(requestContext, _uri); if (cachedToken is null) { cachedToken = await base.GetTokenAsync(requestContext, cancellationToken); _cacheService.InsertNewToken((AccessToken)cachedToken, requestContext, _uri); } } finally { _semaphore.Release(); } } return (AccessToken)cachedToken; } }
委托处理程序代码
public class StorageApiAuthorizeRequestHandler : DelegatingHandler { private readonly IAzureCredentialCacheService _credentialCacheService; private readonly GeneralSection _generalConfig; private readonly StorageApiSection _storageConfig; public StorageApiAuthorizeRequestHandler(IAzureCredentialCacheService credentialCacheService, IOptions<StorageApiSection> storageConfig, IOptions<GeneralSection> generalConfig) { _credentialCacheService = credentialCacheService; _generalConfig = generalConfig.Value; _storageConfig = storageConfig.Value; } protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { var credential = new AzureCredentialCached(_credentialCacheService, new Uri(_storageConfig.Address, UriKind.Absolute), new Azure.Core.TokenCredential[] { new ManagedIdentityCredential(_generalConfig.ManagedIdentityClientId), new VisualStudioCredential() }); var scopes = new[] { _storageConfig.Scope }; var accessToken = (await credential.GetTokenAsync(new Azure.Core.TokenRequestContext(scopes))).Token; request.Headers.Add(HeaderNames.Authorization, $"Bearer {accessToken}"); try { return await base.SendAsync(request, cancellationToken); } catch (Exception ex) { throw; } } }
错误堆栈信息
The archive entry was compressed using an unsupported compression method. at System.IO.Compression.Inflater.Inflate(FlushCode flushCode) at System.IO.Compression.Inflater.ReadInflateOutput(Byte* bufPtr, Int32 length, FlushCode flushCode, Int32& bytesRead) at System.IO.Compression.Inflater.ReadOutput(Byte* bufPtr, Int32 length, Int32& bytesRead) at System.IO.Compression.Inflater.InflateVerified(Byte* bufPtr, Int32 length) at System.IO.Compression.DeflateStream.CopyToStream.<WriteAsyncCore>d__10.MoveNext() at System.IO.Stream.<<CopyToAsync>g__Core|29_0>d.MoveNext() at System.IO.Compression.DeflateStream.CopyToStream.<CopyFromSourceToDestinationAsync>d__6.MoveNext() at System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable.ConfiguredValueTaskAwaiter.GetResult() at System.Net.Http.HttpContent.<<CopyToAsync>g__WaitAsync|56_0>d.MoveNext() at System.Net.Http.MultipartContent.<SerializeToStreamAsyncCore>d__23.MoveNext() at System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable.ConfiguredValueTaskAwaiter.GetResult() at System.Net.Http.HttpContent.<<CopyToAsync>g__WaitAsync|56_0>d.MoveNext() at System.Net.Http.HttpConnection.<SendRequestContentAsync>d__70.MoveNext() at System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable.ConfiguredValueTaskAwaiter.GetResult() at System.Net.Http.HttpConnection.<SendAsyncCore>d__64.MoveNext() at System.Net.Http.HttpConnection.<SendAsyncCore>d__64.MoveNext() at System.Net.Http.HttpConnectionPool.<SendWithVersionDetectionAndRetryAsync>d__84.MoveNext() at System.Net.Http.DiagnosticsHandler.<SendAsyncCore>d__8.MoveNext() at System.Threading.Tasks.ValueTask`1.get_Result() at System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable`1.ConfiguredValueTaskAwaiter.GetResult() at System.Net.Http.RedirectHandler.<SendAsync>d__4.MoveNext() at Microsoft.Extensions.Http.Logging.LoggingHttpMessageHandler.<SendAsync>d__5.MoveNext() at MyAPP.ApiAuthentication.StorageApiAuthorizeRequestHandler.<SendAsync>d__4.MoveNext() in C:\MyAPP\ApiAuthentication\StorageApiAuthorizeRequestHandler.cs:line 37
内容的提问来源于stack exchange,提问作者Adrian Stanisławski
相关产品推荐
相关产品推荐

