An HttpRequestMessage
对象只能使用一次;未来尝试使用同一对象会抛出异常。我正在使用 Polly 重试一些请求,但遇到了这个问题。我知道如何克隆请求,有很多关于 SO 的示例,但我不知道如何克隆请求并在 Polly 重试时发送新请求。我怎样才能做到这一点?
这些是我的政策,供参考。这是一个 Xamarin 应用程序。我想在网络故障的情况下重试几次,如果响应未经授权,我想使用保存的凭据重新进行身份验证并再次尝试原始请求。
public static PolicyWrap<HttpResponseMessage> RetryPolicy
{
get => WaitAndRetryPolicy.WrapAsync(ReAuthPolicy);
}
private static IAsyncPolicy WaitAndRetryPolicy
{
get => Policy.Handle<WebException>().WaitAndRetryAsync(4, _ => TimeSpan.FromSeconds(2));
}
private static IAsyncPolicy<HttpResponseMessage> ReAuthPolicy
{
get => Policy.HandleResult<HttpResponseMessage>(x => x.StatusCode == HttpStatusCode.Unauthorized)
.RetryAsync((_, __) => CoreService.LogInWithSavedCredsAsync(true));
}
这不起作用,因为HttpRequestMessage
重用,但这就是我想要实现的目标:
var request = new HttpRequestMessage(HttpMethod.Post, "some_endpoint")
{
Content = new StringContent("some content")
};
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var policyResponse = await ConnectivityHelper.RetryPolicy
.ExecuteAndCaptureAsync(() => _client.SendAsync(request)).ConfigureAwait(false);
// handle outcome
要抛出的代码InvalidOperationException
if an HttpRequestMessage
被重用是一个验证步骤HttpClient
itself.
源代码链接
private static void CheckRequestMessage(HttpRequestMessage request)
{
if (!request.MarkAsSent())
{
throw new InvalidOperationException(SR.net_http_client_request_already_sent);
}
}
源代码链接
internal bool MarkAsSent()
{
return Interlocked.Exchange(ref sendStatus, messageAlreadySent) == messageNotYetSent;
}
您可以将 polly 重试策略放在DelegatingHandler
那行得通。它还提供了一个很好的 SoC(关注点分离)。如果将来你想not重试或更改重试行为,您只需删除DelegatingHandler
或者改变它。注意废弃HttpRequestMessage
和中间体HttpResponseMessage
的对象。这是我使用的效果很好的一个(重试政策).
你的问题是一个开放式的,一般来说,这样对那些人来说并不好(see)。但就这样吧。我将其称为“反应式”方法,因为它一直使用令牌直到其 ttl,并获取新令牌。请注意,使用令牌 ttl 不会引发 401。
# gets token with its ttl
tokenService: iTokenService
# use retry policy in DH here
httpClient
string getTokenAsync():
# calls out for token
# note: tokens typically have a ttl
# returns cached token till its tll, or gets a new token which is then cached
cachedTokenService: iCachedTokenService
tokenCached
tokenTtl
iTokenService
string getTokenAsync():
# returns tokenCached or gets a new token based on ttl
# note: fetches with some buffer before ttl to avoid failures on edge
# note: buffer as 2x http timeout is good enough
# DH that adds the cached token to the outgoing "work" request
tokenHandler: delegatingHandler
iCachedTokenService
task<response> sendAsync(request, ct):
# gets token, and adds token to request header
# worker service
workService: iWorkService
# uses tokenHandler DH
httpClient
workAsync():
# ...
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)