HttpStatusCode.Unauthorized 后使用 Polly 重试
Using Polly to retry after HttpStatusCode.Unauthorized
我正在调用外部 API 并且想要处理调用 returns 和 Unauthorized
HttpResponseMessage
的事件。发生这种情况时,我想刷新访问令牌并再次拨打电话。
我正在尝试通过以下代码使用 Polly
:
public async Task<HttpResponseMessage> MakeGetRequestAsync()
{
var retryPolicy = Policy
.HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.Unauthorized)
.Retry(1, (exception, retryCount) =>
{
RefreshAccessToken();
});
var result = await retryPolicy.ExecuteAsync(() => CallApiAsync());
return result;
}
private async Task<HttpResponseMessage> CallApiAsync()
{
var url = Options.ResourceSandboxUrl;
var httpClient = new HttpClient();
SetRequestHeaders(httpClient);
var response = await httpClient.GetAsync(url);
response.StatusCode = HttpStatusCode.Unauthorized;
return response;
}
I put breakpoints on the ExecuteAsync
statement and in DoSomethingAsync
- when I step over ExecuteAsync
DoSomethingAsync
is not called and control is returned to the function that called MakeGetRequestAsync
我不明白为什么 DoSomethingAsync
没有被调用 - 谁能帮助我实现我想要实现的目标?
我查看了 Stack Overflow 上的 Polly 文档和 Polly 问题,但我无法弄清楚发生了什么..
这就是异步等待在 .net 中的工作方式,当您的代码执行到 await
时,会发生两件事
您的代码的当前线程应该释放以使您的代码异步,这意味着您的方法应该 return
当您等待的任务完成时,您的方法应该从原来的地方继续
要使用 ExecuteAsync()
,您必须将策略声明为 .RetryAsync(...)
,而不是 .Retry(...)
。
如果您的实际代码与上面的代码示例完全一致,.ExecuteAsync(...)
将因 .Retry(...)
[同步策略] 和 .ExecuteAsync(...)
[异步执行] 之间的不匹配而抛出].由于抛出此异常,因此 CallApiAsync()
确实从未被调用。调用 MakeGetRequestAsync()
时,您应该能够看到抛出的异常
总体代码方法看起来不错:这个 retry-refreshing-authentication 是 proven pattern with Polly!
我回答这个老问题只是为了指出官方记录此模式的 Polly wiki 页面:
retry-to-refresh-authorization
特别是建议的代码片段:
var authorisationEnsuringPolicy = Policy
.HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.Unauthorized)
.RetryAsync(
retryCount: 1, // Consider how many retries. If auth lapses and you have valid credentials, one should be enough; too many tries can cause some auth systems to blacklist.
onRetryAsync: async (outcome, retryNumber, context) => FooRefreshAuthorizationAsync(context),
/* more configuration */);
var response = authorisationEnsuringPolicy.ExecuteAsync(context => DoSomethingThatRequiresAuthorization(context), cancellationToken);
The FooRefreshAuthorizationAsync(...)
method can obtain a new authorization token and pass it to the delegate executed through the policy using Polly.Context
.
我正在调用外部 API 并且想要处理调用 returns 和 Unauthorized
HttpResponseMessage
的事件。发生这种情况时,我想刷新访问令牌并再次拨打电话。
我正在尝试通过以下代码使用 Polly
:
public async Task<HttpResponseMessage> MakeGetRequestAsync()
{
var retryPolicy = Policy
.HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.Unauthorized)
.Retry(1, (exception, retryCount) =>
{
RefreshAccessToken();
});
var result = await retryPolicy.ExecuteAsync(() => CallApiAsync());
return result;
}
private async Task<HttpResponseMessage> CallApiAsync()
{
var url = Options.ResourceSandboxUrl;
var httpClient = new HttpClient();
SetRequestHeaders(httpClient);
var response = await httpClient.GetAsync(url);
response.StatusCode = HttpStatusCode.Unauthorized;
return response;
}
I put breakpoints on the
ExecuteAsync
statement and inDoSomethingAsync
- when I step overExecuteAsync
DoSomethingAsync
is not called and control is returned to the function that calledMakeGetRequestAsync
我不明白为什么 DoSomethingAsync
没有被调用 - 谁能帮助我实现我想要实现的目标?
我查看了 Stack Overflow 上的 Polly 文档和 Polly 问题,但我无法弄清楚发生了什么..
这就是异步等待在 .net 中的工作方式,当您的代码执行到 await
时,会发生两件事
您的代码的当前线程应该释放以使您的代码异步,这意味着您的方法应该 return
当您等待的任务完成时,您的方法应该从原来的地方继续
要使用 ExecuteAsync()
,您必须将策略声明为 .RetryAsync(...)
,而不是 .Retry(...)
。
如果您的实际代码与上面的代码示例完全一致,.ExecuteAsync(...)
将因 .Retry(...)
[同步策略] 和 .ExecuteAsync(...)
[异步执行] 之间的不匹配而抛出].由于抛出此异常,因此 CallApiAsync()
确实从未被调用。调用 MakeGetRequestAsync()
总体代码方法看起来不错:这个 retry-refreshing-authentication 是 proven pattern with Polly!
我回答这个老问题只是为了指出官方记录此模式的 Polly wiki 页面:
retry-to-refresh-authorization
特别是建议的代码片段:
var authorisationEnsuringPolicy = Policy
.HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.Unauthorized)
.RetryAsync(
retryCount: 1, // Consider how many retries. If auth lapses and you have valid credentials, one should be enough; too many tries can cause some auth systems to blacklist.
onRetryAsync: async (outcome, retryNumber, context) => FooRefreshAuthorizationAsync(context),
/* more configuration */);
var response = authorisationEnsuringPolicy.ExecuteAsync(context => DoSomethingThatRequiresAuthorization(context), cancellationToken);
The
FooRefreshAuthorizationAsync(...)
method can obtain a new authorization token and pass it to the delegate executed through the policy usingPolly.Context
.