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

如何在RequestInterceptor中区分多端点设置请求头,解决Feign调用Bearer token为空问题

问题排查与修复方案

核心错误点

    1. Feign接口方法定义错误:/oauth/token对应的接口方法被定义为static,且直接返回空的BasicAuthResponse实例。Feign只会代理接口的非静态抽象方法,静态方法不会触发远程调用,导致永远拿不到真实接口返回的token。
    1. 请求拦截器头覆盖问题:拦截器中先判断如果是/oauth/token请求设置Basic Auth头,但是后续无判断直接覆盖Authorization头为Bearer格式,导致/oauth/token请求实际携带的是无效的Bearer头,无法通过Basic Auth校验。
    1. Basic Auth格式错误:
    • 拼接凭证时错误使用用户名+用户名,正确应该是用户名+密码
    • 生成的Basic Auth头缺少Basic 前缀,服务端无法识别这是Basic Auth凭证
    1. Token获取逻辑未走Feign代理:SomeAuthTokenSupplier中调用getBasicAuthToken()调用的是静态方法,没有走Feign客户端的代理逻辑,不会发起真实的远程请求。

修复步骤

第一步:修正Feign接口定义

把/oauth/token的方法改成非静态抽象方法,删除写死的返回值:

@PostMapping("/oauth/token")
BasicAuthResponse getBasicAuthToken();

第二步:修正拦截器的头设置逻辑

调整顺序,只有非/oauth/token的请求才设置Bearer头,避免覆盖,同时修正Basic Auth的格式:

@Bean
public RequestInterceptor someAuthInterceptor() {
  return template -> {
    if(template.url().equals("/oauth/token")) {
      // 修正凭证拼接规则为用户名:密码,增加标准Basic前缀
      String credential = properties.getCredentials().getUser() + ":" + properties.getCredentials().getPassword();
      String authToken = "Basic " + Base64Utils.encodeToString(credential.getBytes(StandardCharsets.UTF_8));
      template.header("Authorization", authToken);
    } else {
      // 仅业务接口添加Bearer头
      template.header("Authorization", String.format("Bearer %s", tokenSupplier.getToken()));
    }
  };
}

第三步:修正Token获取逻辑,走Feign代理发起请求

注入ApplicationContext懒加载Feign客户端实例,避免循环依赖,发起真实的token获取请求:

@AllArgsConstructor
class SomeClientConfig extends BaseClientConfig {
  private final SomeProperties properties;
  // 新增注入Spring上下文
  private final ApplicationContext applicationContext;
  private final SomeAuthTokenSupplier tokenSupplier = new SomeAuthTokenSupplier();

  // 原有apacheClient、retryer等Bean逻辑保持不变

  private class SomeAuthTokenSupplier {
    private volatile String token;
    private volatile long retrievedOn = -1L;
    // 懒加载获取Feign代理实例,避免循环依赖
    private someClient getClient() {
      return applicationContext.getBean(someClient.class);
    }

    String getToken() {
      if (updateTokenRequired()) {
        synchronized (this) {
          if (updateTokenRequired()) {
            // 走Feign代理发起真实的远程请求获取token
            BasicAuthResponse tokenResponse = getClient().getBasicAuthToken();
            token = tokenResponse.getAccess_token();
            retrievedOn = Instant.now().toEpochMilli();
          }
        }
      }
      return token;
    }
    // 原有updateTokenRequired逻辑保持不变
  }
}

可选优化

  • 建议按照Java命名规范将Feign接口名someClient调整为大驼峰格式SomeClient,避免语法规范警告
  • 可以直接使用/oauth/token接口返回的expires_in字段判断token有效期,比硬编码8小时更符合对接接口的规则

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 11:15:01