我有一个改装客户端,它可以帮助我为我对REST API发出的任何请求设置标头。在用户登录时,我从服务器获取令牌并将此令牌设置为请求的标头。我将此令牌保存到SharedPreferences,以便我可以在需要向REST API发出请求时随时获取它。问题是,当新用户登录时,无论何时我将新令牌设置到我的SharedPreferences文件,它仍然会获得旧令牌,而不是保存此新令牌以用于将来的请求。
这是我的改造客户端:
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();
}
这是我调用我的set token方法将新令牌保存到SharedPreference
的地方 authUser.setToken(token);
答案 0 :(得分:2)
我完全不明白这是多么令人惊讶。你的RetrofitClient
是一个令人困惑(并且可以说是写得很糟糕)的单身人士。让我们来看看这会失败的典型情况。
您使用之前保存的令牌启动您的应用。起初一切正常。在某些时候,您调用RetrofitClient.getClient(token)
并且所有请求都成功。一段时间后,服务器使令牌无效。您可能会从服务器收到403响应,再次登录屏幕并在SharedPreferences中更新您的令牌。这是你的问题开始的地方。虽然您正确保存了新令牌,但RetrofitClient
会执行单身人士所做的事情并继续返回private static Retrofit retrofit
字段中存储的第一个实例。
快速解决方法是向RetrofitClient
添加无效方法。像。的东西。
public static void invalidate() {
this.retrofit = null;
}
当您收到403回复或退出时,请致电。
PS:请在if (retrofit==null) {
方法的开头移动以下行getClient
。每次有人打电话getClient
时都无需创建新的okHttp客户端,这只是浪费。
答案 1 :(得分:0)
您可以在网络请求发生前每次执行intercepter执行。将新文件创建为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);
}
}
将intercepter添加到okHttpclient
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.addInterceptor(new HeaderIntercepter());