我有一个应用程序,它请求需要通过access_token
进行身份验证的服务。
我的想法是,如果access_token
已过期,则使用Polly进行重试。
我在.NET Core 3.1应用程序中使用Refit(v5.1.67)和Polly(v7.2.1)。
服务注册如下:
services.AddTransient<ExampleDelegatingHandler>();
IAsyncPolicy<HttpResponseMessage> retryPolicy = Policy<HttpResponseMessage>
.Handle<ApiException>()
.RetryAsync(1, (response, retryCount) =>
{
System.Diagnostics.Debug.WriteLine($"Polly Retry => Count: {retryCount}");
});
services.AddRefitClient<TwitterApi>()
.ConfigureHttpClient(c =>
{
c.BaseAddress = new Uri("https://api.twitter.com/");
})
.AddHttpMessageHandler<ExampleDelegatingHandler>()
.AddPolicyHandler((sp, req) =>
{
//this policy does not works, because the exception is not catched on
//"Microsoft.Extensions.Http.PolicyHttpMessageHandler" (DelegatingHandler)
return retryPolicy;
});
public interface TwitterApi
{
[Get("/2/users")]
Task<string> GetUsers();
}
public class ExampleDelegatingHandler : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
try
{
return await base.SendAsync(request, cancellationToken);
}
catch (Exception)
{
//Why do not catch the exception?
throw;
}
}
}
重试策略不起作用!
通过分析问题,我意识到异常没有在HttpClient的DelegatingHandler
中捕获。由于AddPolicyHandler
语句生成一个DelegatingHandler
(PolicyHttpMessageHandler
)来执行策略,而异常没有在那里被捕获,因此策略从未执行。我意识到该问题仅发生在异步情况下,其中请求可以被发送。在同步情况下它是可以工作的(例如:超时)。
为什么异常在DelegatingHandler
中没有被捕获?
我附加了一个模拟Twitter调用的示例项目。
https://www.dropbox.com/s/q1797rq1pbjvcls/ConsoleApp2.zip?dl=0
外部引用:
https://github.com/reactiveui/refit#using-httpclientfactory
https://www.hanselman.com/blog/UsingASPNETCore21sHttpClientFactoryWithRefitsRESTLibrary.aspx
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-3.1
MessageHandler
有什么特别的原因吗?此外,你可以通过传递策略本身来简化AddPolicyHandler
的调用:.AddPolicyHandler(retryPolicy);
- Peter Csala