为何Retrofit的Authenticator未被调用?423转401后无触发
问题分析与解决方案
你的问题核心在于拦截器的类型选错了,导致Authenticator根本看不到你修改后的401响应码。
为什么Authenticator没被触发?
OkHttp的拦截器分为两种:应用拦截器(addInterceptor)和网络拦截器(addNetworkInterceptor),它们的执行顺序完全不同:
- 请求流程:应用拦截器 → 网络拦截器 → 发送网络请求 → 收到网络响应
- 响应处理流程:网络响应 → 网络拦截器 → 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
相关产品推荐
相关产品推荐

