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

如何在单个方法中调用Action、Func并自动处理Token过期重试

解决Token过期自动重试并动态传递签名参数的问题

核心解决方案:利用闭包捕获动态参数

不需要在InvokeMethodRefreshToken内部直接处理CreateSignature的参数变化,而是在调用封装方法时,通过匿名委托闭包捕获当前请求的uri、body等参数,把带参数的CreateSignature调用包装成无参的Action传递进去。闭包会保留当前请求的参数上下文,确保CreateSignature能适配不同请求的参数变化。

修正后的完整代码

1. 优化InvokeMethodRefreshToken方法(增加类型安全检查)

private async Task<T> InvokeMethodRefreshToken<T>(Action createSignature, Func<Task<T>> func)
{
    var result = await func.Invoke();
    
    // 用模式匹配确保类型安全,避免空引用异常
    if (result is BaseResponse baseResponse && baseResponse.Message == "Token Expired")
    {
        var token = await GetAccessToken();
        if (!string.IsNullOrWhiteSpace(token.AccessToken))
        {
            // 闭包自动携带当前请求的参数,重新生成签名
            createSignature.Invoke();
            // 重试请求
            result = await func.Invoke();
        }
        else
        {
            // 获取Token失败,将错误信息复制到结果中
            result = (T)token.Copy(result.GetType());
        }
    }

    return result;
}

2. 修正GetBalance方法的调用逻辑

在调用InvokeMethodRefreshToken时,用匿名委托捕获当前请求的uri和body,包装成无参Action传递:

private async Task<Balance> GetBalance()
{
    string uri = "/user/balance";
    var body = new 
    {
        phoneAccount = "xxx"
    };
    
    // 匿名委托捕获uri、body,包装成无参Action;请求逻辑也要包装成Func<Task<T>>
    return await InvokeMethodRefreshToken(
        () => CreateSignature(uri, body), 
        () => httpClient.PostJson<Balance>(uri, body)
    );
}

3. 辅助方法保持不变

private async Task<Token> GetAccessToken()
{
    // 实现获取并更新AccessToken的逻辑,比如设置HttpClient的Bearer Token头
    var token = await /* 调用获取Token的API */;
    if (!string.IsNullOrWhiteSpace(token.AccessToken))
    {
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.AccessToken);
    }
    return token;
}

private void CreateSignature(string uri, object body)
{
    // 根据当前uri、body和AccessToken生成签名,并设置到请求头
    var signature = /* 签名生成逻辑 */;
    httpClient.DefaultRequestHeaders.Add("Signature", signature);
}

关键说明

  • 闭包的作用:匿名委托() => CreateSignature(uri, body)会捕获当前方法的uri和body变量,即使在InvokeMethodRefreshToken内部调用,也会使用捕获的参数执行签名生成,完美适配不同请求的参数差异。
  • 委托传递注意事项:PostJson方法必须包装成Func<Task<T>>(即() => httpClient.PostJson<Balance>(uri, body)),否则会立即执行请求,而非传递请求逻辑。
  • 类型安全优化:使用result is BaseResponse baseResponse的模式匹配,避免强制转换后的空引用问题,提升代码健壮性。

可选优化:增加重试次数限制

为避免Token过期后重试仍失败导致的无限循环,可给封装方法增加重试次数参数:

private async Task<T> InvokeMethodRefreshToken<T>(Action createSignature, Func<Task<T>> func, int maxRetryCount = 1)
{
    var retryCount = 0;
    T result;
    
    do
    {
        result = await func.Invoke();
        if (result is not BaseResponse baseResponse || baseResponse.Message != "Token Expired")
        {
            break;
        }
        
        retryCount++;
        if (retryCount > maxRetryCount) break;
        
        var token = await GetAccessToken();
        if (string.IsNullOrWhiteSpace(token.AccessToken))
        {
            result = (T)token.Copy(result.GetType());
            break;
        }
        
        createSignature.Invoke();
    } while (retryCount <= maxRetryCount);

    return result;
}

内容的提问来源于stack exchange,提问作者derodevil

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 11:23:18