You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Refit中结合Polly重试时无法刷新Token的问题

问题分析与解决方案

你的问题核心在于:重试时使用的仍是最初调用接口时传入的旧Token。因为Device_GetAllAsync(await GetToken())在第一次调用前就已经获取了Token并传入方法,Polly重试只是重复执行这个已经绑定了旧Token的方法调用,不会重新执行await GetToken(),所以哪怕你刷新了Token,重试请求依然用的是旧值。

解决方案:改用请求头自动注入Token,而非方法参数传递

1. 修改Refit接口,移除Token参数

把Token从方法参数中移除,改为通过请求头自动添加:

public interface IHomeMonitorRestClient
{
    [Get("/Device")]
    Task<IEnumerable<Model.Device>> Device_GetAllAsync();
}

2. 新增Token注入Handler

创建一个DelegatingHandler,负责在每次请求(包括重试)时自动从AuthService获取最新Token并添加到请求头:

public class TokenAuthorizationHandler : DelegatingHandler
{
    private readonly AuthService _authService;

    public TokenAuthorizationHandler(AuthService authService)
    {
        _authService = authService;
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        // 每次请求都获取当前最新的Token
        var currentToken = await _authService.GetCurrentToken(); 
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", currentToken);
        return await base.SendAsync(request, cancellationToken);
    }
}

注:需要在AuthService中新增GetCurrentToken()方法,返回当前有效的Token(刷新后会更新这个值)

3. 调整Rest客户端注册逻辑

把Token注入Handler添加到HttpClient管道中,同时保留原有Polly策略:

private static void AddRestClient(IServiceCollection services, string hMClientBaseUrl, AuthService authService)
{
    var unauthPolicy = Policies.GetUnauthPolicy(authService);

    services.AddRefitClient<IHomeMonitorRestClient>(new RefitSettings
    {
        ContentSerializer = new NewtonsoftJsonContentSerializer(DefaultJsonSettings.Settings),
    })
        .ConfigureHttpClient(c => c.BaseAddress = new Uri(hMClientBaseUrl))
        .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
        {
            ServerCertificateCustomValidationCallback = (message, cert, chain, sslErrors) => true
        })
        .AddHttpMessageHandler(() => new TokenAuthorizationHandler(authService)) // 注入Token处理Handler
        .AddPolicyHandler(unauthPolicy);
}

4. 简化API调用代码

现在调用接口不需要手动传Token了:

var devices = await _hmRestClient.Device_GetAllAsync();

5. 保留原有Polly策略逻辑

你的重试策略无需大改,只要确保RefreshToken()方法能正确更新AuthService内部的Token存储即可:

public static AsyncRetryPolicy<HttpResponseMessage> GetUnauthPolicy(AuthService authService)
{
    return Policy.HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.Unauthorized)
        .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(1), async (response, timespan, retryNo, context) =>
        {
            await authService.RefreshToken(); // 刷新后,AuthService内部的Token会更新
        });
}

为什么这个方案能解决循环问题?

每次请求(包括Polly触发的重试)都会经过TokenAuthorizationHandler,它会实时从AuthService获取最新的Token,刷新Token后的重试请求自然会使用新Token,不会再重复触发未授权错误。

内容的提问来源于stack exchange,提问作者jason.kaisersmith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 03:48:08