- Primär: HttpClientHandler ()
Code: Select all
AllowAutoRedirect = false - Delegieren: .AddHttpMessageHandler()
- Outermost: .AddResilienceHandler(...) mit:
Code: Select all
HttpRetryStrategyOptions { MaxRetryAttempts = 1, Delay = TimeSpan.Zero } - = 401
Code: Select all
ShouldHandle - ruft IAuthenticationTokenCache.ForceRefreshApiTokenAsync() auf (Singleton-Cache)
Code: Select all
OnRetry
Der Auth-Handler stempelt einen Header pro Versuch:
Code: Select all
protected override async Task SendAsync(HttpRequestMessage request, CancellationToken ct)
{
request.Headers.Remove("X-Auth-Handler-Stamp");
request.Headers.TryAddWithoutValidation("X-Auth-Handler-Stamp", Guid.NewGuid().ToString("N"));
var jwt = await _tokenCache.GetTokenForApi().ConfigureAwait(false);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", jwt);
return await base.SendAsync(request, ct).ConfigureAwait(false);
}
Code: Select all
services.AddHttpClient("my-http-client")
.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
{
AllowAutoRedirect = false
})
.AddHttpMessageHandler()
.AddResilienceHandler("RetryOnUnauthorized", (builder, sp) =>
{
var cache = sp.GetRequiredService(); // singleton
builder.AddRetry(new HttpRetryStrategyOptions
{
MaxRetryAttempts = 1,
Delay = TimeSpan.Zero,
ShouldHandle = new PredicateBuilder()
.HandleResult(r => r.StatusCode == HttpStatusCode.Unauthorized),
OnRetry = async _ => await cache.ForceRefreshApiTokenAsync().ConfigureAwait(false)
});
});
Beim ersten 401 versucht der Resilience-Handler erneut, die gesamte Pipeline wird erneut ausgeführt und X-Auth-Handler-Stamp ändert sich.
Tatsächlich:
Ich sehe zwei HTTP-Aufrufe, aber die exakt gleichen Header (einschließlich X-Auth-Handler-Stamp) werden beide Male gesendet – als ob dieselbe HttpRequestMessage erneut gesendet würde und der Authentifizierungshandler nicht erneut ausgeführt würde.
Hinweise:
- Es wird der korrekt benannte Client verwendet.
- Cache ist Singleton und wird aktualisiert korrekt.
- Keine Weiterleitungen, keine Proxy-Authentifizierung, Inhalte sind wiederverwendbar.
- Das Hinzufügen von .Handle() hat das Verhalten nicht geändert.
Gibt es eine Situation, in der das erneute Senden innerhalb von HttpClientHandler erfolgt (umgeht). Handler delegieren), oder verstehe ich das Wiederholungsverhalten/die Wiederholungsreihenfolge falsch? Was muss ich tun, um sicherzustellen, dass der Auth-Handler so ausgeführt wird, dass er das neue Token abruft?
Was ich versucht habe
- Die Pipeline wurde mit IHttpClientFactory erstellt:
(Code: Select all
HttpClientHandler)Code: Select all
AllowAutoRedirect = false Code: Select all
.AddHttpMessageHandler()- last mit HttpRetryStrategyOptions hinzugefügt (Wiederholung bei 401, MaxRetryAttempts = 1, Delay = TimeSpan.Zero).
Code: Select all
.AddResilienceHandler(...)
- Singleton (sowohl vom Handler als auch von OnRetry verwendet).
Code: Select all
IAuthenticationTokenCache - Handler delegieren Transient.
[*]Im Auth-Handler wurde ein Header pro Versuch gestempelt und bei jedem Versand überschrieben:
Code: Select all
request.Headers.Remove("X-Auth-Handler-Stamp");
request.Headers.TryAddWithoutValidation("X-Auth-Handler-Stamp", Guid.NewGuid().ToString("N"));
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", jwt);
Code: Select all
private static readonly HttpRequestOptionsKey AttemptKey = new("Attempt");
request.Options.TryGetValue(AttemptKey, out var attempt);
request.Options.Set(AttemptKey, attempt + 1);
- Erster Aufruf mit altem Token → gibt 401 zurück und erweitert das Szenario.
- 2. Aufruf mit neuem Token → sollte 200 zurückgeben.
[*]Bestätigter Anforderungsinhalt ist wiederverwendbar (keine nicht durchsuchbaren Streams).
Was ich erwartet habe
- Bei einem 401 sollte der Resilienz-Wiederholungsversuch erneut in die gesamte Pipeline eintreten, also:
wird zweimal ausgeführt (einmal pro Versuch).Code: Select all
AuthenticationDelegatingHandler.SendAsync - (GUID) ändert sich zwischen Versuchen.
Code: Select all
X-Auth-Handler-Stamp - -Header wird beim erneuten Versuch mit dem aktualisierten Token überschrieben.
Code: Select all
AuthorizationDer - WireMock gleicht den zweiten Aufruf mit dem neuen Token ab und gibt 200 zurück.
Was tatsächlich passiert
- Ich sehe zwei HTTP-Aufrufe, aber:
ist in beiden Fällen identisch.Code: Select all
X-Auth-Handler-Stamp - Header auf Wire-Ebene sind identisch; Es sieht so aus, als ob die dieselbe HttpRequestMessage erneut gesendet wurde.
- Dies deutet darauf hin, dass das erneute Senden möglicherweise unter den delegierenden Handlern (innerhalb von HttpClientHandler) erfolgt oder der Authentifizierungshandler beim Wiederholungsversuch nicht erneut aufgerufen wird.
Jede minimale Reproduktion/Korrektur willkommen.
Mobile version