使用新的请求拦截器假装客户端重试器?

Posted

技术标签:

【中文标题】使用新的请求拦截器假装客户端重试器?【英文标题】:Feign client Retryer with a new request interceptor? 【发布时间】:2019-04-29 06:11:09 【问题描述】:

我目前正在手动构建一个 feign 客户端并将拦截器传递给它以进行授权。我想为一些响应代码提供一个更智能的重试器。

public class myErrorEncoder extends ErrorDecoder.Default 

@Override
public Exception decode(final String methodKey, final Response response) 
    if (response.status() == 401) 
        String token = refreshToken();  // I would like to refresh the token and Edit the client
        return new RetryableException("Token Expired will retry it", null);
     else 
        return super.decode(methodKey, response);
    

拦截器

@Bean public CustomInterceptor getInterceptor(String token) 
    return new CustomInterceptor(token);

假装建造者

 private <T> T feignBuild(final Class<T> clazz, final String uri, final String token) 
    return Feign
            .builder().client(new ApacheHttpClient())
            .encoder(new GsonEncoder())
            .decoder(new ResponseEntityDecoder(feignDecoder())
            .retryer(new Retryer.Default(1,100,3))
            .errorDecoder(new ErrorDecoder())
            .requestInterceptor(getInterceptor(token))
            .contract(new ClientContract())
            .logger(new Slf4jLogger(clazz)).target(clazz, uri);

现在我想用刷新的令牌更新 feign 客户端并重试。 有没有办法访问客户端实例并对其进行配置。

【问题讨论】:

【参考方案1】:

您对拦截器的使用不正确。拦截器在重试期间被重新应用,但它们只被实例化一次并且被期望是线程安全的。要实现您要寻找的内容,需要将令牌生成与拦截器分开,并让拦截器请求新令牌。

public class TokenInterceptor() 
   TokenService tokenService;

   public TokenInterceptor(TokenService tokenService) 
      this.tokenService = tokenService;
   

   public void apply(RequestTemplate template) 
      /* getToken() should create a new token */
      String token = this.tokenService.getToken();
      template.header("Authorization", "Bearer " + token);
   

这将确保每个重试周期都会创建一个新令牌。

【讨论】:

以这种方式处理它意味着为每个请求生成一个新令牌。这不是最佳的。我希望仅在 401 错误代码上生成令牌。 您需要添加逻辑以确定在请求新令牌之前是否需要令牌。您可以使用ErrorDecoder 捕获401清除令牌并返回RetryableException 以重试请求。 @KevinDavis 如果我错了,请纠正我,但您提出的解决方案将在另一个 Authorization 标头中附加新令牌。你如何替换现有的?

以上是关于使用新的请求拦截器假装客户端重试器?的主要内容,如果未能解决你的问题,请参考以下文章

反应式假装客户端全局重试

改造:如何从 okhttp 拦截器再次重试请求?

Angular 7 - 如何在某些响应状态代码上重试 http 请求?

RestKit ,如果是由于令牌过期引起的,则拦截失败的请求/重试

使用多个请求刷新访问令牌

Axios 中的单元测试拦截器逻辑