改造无法将新令牌设置为请求的 Header
Retrofit unable to set new Token to Header of Requests
我有一个改装客户端,可以帮助我为我对 REST API 发出的任何请求设置 header。在用户登录时,我从服务器获取令牌并将此令牌设置为请求的 header。我将此令牌保存到 SharedPreferences,以便我可以在需要向我的 REST API 发出请求时随时获取它。问题是,每当我在新用户登录时为我的 SharedPreferences 文件设置一个新令牌时,它仍然会获得旧令牌,而不是保存这个新令牌以用于将来的请求。
下面是我的 Retrofit 客户端:
public class RetrofitClient {
private static Retrofit retrofit = null;
public static Retrofit getClient(String token) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient okClient = new OkHttpClient();
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
.create();
okClient.interceptors().add(chain -> chain.proceed(chain.request()));
okClient.interceptors().add(chain -> {
Request original = chain.request();
Request request = original.newBuilder()
.header(Config.X_AUTH_TOKEN, "Bearer" + " " + token)
.method(original.method(), original.body())
.build();
Log.d("Authorization", token);
return chain.proceed(request);
});
okClient.interceptors().add(logging);
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(Config.BASE_URL1)
.client(okClient)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
return retrofit;
}
}
这是我设置和获取令牌的代码
public String getToken() {
return prefs.getString(AuthUser.USER_TOKEN, "");
}
public void setToken(String token) {
SharedPreferences.Editor editor = prefs.edit();
editor.putString(AuthUser.USER_TOKEN, token);
editor.apply();
}
这是我调用设置令牌方法将新令牌保存到 SharedPreference 的地方
authUser.setToken(token);
我完全不明白这有什么好惊讶的。您的 RetrofitClient
是一个令人困惑(并且可以说写得很糟糕)的单身人士。让我们来看一个失败的典型情况。
您使用之前保存的令牌启动您的应用程序。起初一切正常。在某个时候,您调用 RetrofitClient.getClient(token)
并且所有请求都成功。一段时间后,服务器使令牌无效。您可能会从您的服务器收到 403 响应,再次启动登录屏幕并在您的 SharedPreferences 中更新您的令牌。这是您的问题开始的地方。尽管您正确保存了新令牌,但您的 RetrofitClient
将执行单身人士所做的事情并继续 return 存储在 private static Retrofit retrofit
文件中的自身的第一个实例化。
一个快速的解决方法是向您的 RetrofitClient
添加一个无效方法。有点像。
public static void invalidate() {
this.retrofit = null;
}
在收到 403 响应或注销时调用它。
PS:请将以下行 if (retrofit==null) {
移到 getClient
方法的开头。创建一个新的 okHttp 客户端,没有任何意义,每次有人调用 getClient
都是浪费。
你可以编写拦截器在每次网络请求之前执行happen.Create new file as HeaderIntercepter
public class HeaderIntercepter implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
String token = context.getSharedPreferences(FILENAME, MODE_PRIVATE).getString("TOKEN","");
Request tokenRequest = request.newBuilder()
.addHeader("Authorization", "Bearer " + token)
.addHeader("Content-Type", "application/json")
.build();
return chain
.proceed(tokenRequest);
}
}
为okHttpclient添加拦截器
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.addInterceptor(new HeaderIntercepter());
我有一个改装客户端,可以帮助我为我对 REST API 发出的任何请求设置 header。在用户登录时,我从服务器获取令牌并将此令牌设置为请求的 header。我将此令牌保存到 SharedPreferences,以便我可以在需要向我的 REST API 发出请求时随时获取它。问题是,每当我在新用户登录时为我的 SharedPreferences 文件设置一个新令牌时,它仍然会获得旧令牌,而不是保存这个新令牌以用于将来的请求。
下面是我的 Retrofit 客户端:
public class RetrofitClient {
private static Retrofit retrofit = null;
public static Retrofit getClient(String token) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient okClient = new OkHttpClient();
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
.create();
okClient.interceptors().add(chain -> chain.proceed(chain.request()));
okClient.interceptors().add(chain -> {
Request original = chain.request();
Request request = original.newBuilder()
.header(Config.X_AUTH_TOKEN, "Bearer" + " " + token)
.method(original.method(), original.body())
.build();
Log.d("Authorization", token);
return chain.proceed(request);
});
okClient.interceptors().add(logging);
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(Config.BASE_URL1)
.client(okClient)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
return retrofit;
}
}
这是我设置和获取令牌的代码
public String getToken() {
return prefs.getString(AuthUser.USER_TOKEN, "");
}
public void setToken(String token) {
SharedPreferences.Editor editor = prefs.edit();
editor.putString(AuthUser.USER_TOKEN, token);
editor.apply();
}
这是我调用设置令牌方法将新令牌保存到 SharedPreference 的地方
authUser.setToken(token);
我完全不明白这有什么好惊讶的。您的 RetrofitClient
是一个令人困惑(并且可以说写得很糟糕)的单身人士。让我们来看一个失败的典型情况。
您使用之前保存的令牌启动您的应用程序。起初一切正常。在某个时候,您调用 RetrofitClient.getClient(token)
并且所有请求都成功。一段时间后,服务器使令牌无效。您可能会从您的服务器收到 403 响应,再次启动登录屏幕并在您的 SharedPreferences 中更新您的令牌。这是您的问题开始的地方。尽管您正确保存了新令牌,但您的 RetrofitClient
将执行单身人士所做的事情并继续 return 存储在 private static Retrofit retrofit
文件中的自身的第一个实例化。
一个快速的解决方法是向您的 RetrofitClient
添加一个无效方法。有点像。
public static void invalidate() {
this.retrofit = null;
}
在收到 403 响应或注销时调用它。
PS:请将以下行 if (retrofit==null) {
移到 getClient
方法的开头。创建一个新的 okHttp 客户端,没有任何意义,每次有人调用 getClient
都是浪费。
你可以编写拦截器在每次网络请求之前执行happen.Create new file as HeaderIntercepter
public class HeaderIntercepter implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
String token = context.getSharedPreferences(FILENAME, MODE_PRIVATE).getString("TOKEN","");
Request tokenRequest = request.newBuilder()
.addHeader("Authorization", "Bearer " + token)
.addHeader("Content-Type", "application/json")
.build();
return chain
.proceed(tokenRequest);
}
}
为okHttpclient添加拦截器
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.addInterceptor(new HeaderIntercepter());