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

为何Retrofit的Authenticator未被调用?423转401后无触发

问题分析与解决方案

你的问题核心在于拦截器的类型选错了,导致Authenticator根本看不到你修改后的401响应码。

为什么Authenticator没被触发?

OkHttp的拦截器分为两种:应用拦截器(addInterceptor)和网络拦截器(addNetworkInterceptor),它们的执行顺序完全不同:

  1. 请求流程:应用拦截器 → 网络拦截器 → 发送网络请求 → 收到网络响应
  2. 响应处理流程:网络响应 → 网络拦截器 → Authenticator(如果响应码是401) → 应用拦截器 → 返回给调用者

你现在用addInterceptor添加的响应码修改拦截器,是在Authenticator执行之后才会处理响应。也就是说,Authenticator看到的还是服务器返回的原始423响应,自然不会触发authenticate方法。等Authenticator判断完不执行后,你的拦截器才把响应改成401,这时候已经晚了。

修复方案

把修改响应码的拦截器换成网络拦截器,用addNetworkInterceptor来添加,这样网络响应回来后,先经过这个拦截器把423改成401,然后Authenticator就能看到这个401响应,从而触发刷新令牌的逻辑。

修改后的OkHttpClient配置代码如下:

OkHttpClient httpClient = new OkHttpClient.Builder()
    .connectTimeout(10, TimeUnit.SECONDS)
    .writeTimeout(60, TimeUnit.SECONDS)
    .readTimeout(60, TimeUnit.SECONDS)
    .addInterceptor(new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            // 添加token的应用拦截器,这个位置没问题
            Request request = chain.request();
            Request.Builder builder = request.newBuilder();
            builder.header("Authorization", "access_token");
            return chain.proceed(builder.build());
        }
    })
    // 把这里的addInterceptor改成addNetworkInterceptor
    .addNetworkInterceptor(new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            Response response = chain.proceed(request);
            if (response.code() == 423)
                return response.newBuilder().code(401).build();
            return response;
        }
    })
    .authenticator(new Authenticator() {
        @Override
        public Request authenticate(Route route, Response response) throws IOException {
            // 现在这个方法会被正常触发了
            String newAccessToken = refreshToken();
            saveNewToken(newAccessToken);
            return response.request().newBuilder()
                .header("Authorization", newAccessToken)
                .build();
        }
    })
    .build();

额外注意点

  • 网络拦截器会在每次重试请求时都执行,这刚好符合你刷新令牌后重试请求的场景,逻辑上更合理。
  • 应用拦截器只会在原始请求时执行一次,重试时不会再跑,所以适合用来处理全局的请求头添加这类只需要做一次的操作,就像你添加Authorization头的拦截器那样,放在应用拦截器里是对的。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:32:48