Retrofit无法将新令牌设置为请求标头

问题描述 投票:2回答:2

我有一个改装客户端,可帮助我为我的REST API请求设置标头。在用户登录时,我从服务器获取令牌并将此令牌设置为请求的标头。我将此令牌保存到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();
}

这是我调用我的set token方法将新令牌保存到SharedPreference的地方

 authUser.setToken(token);
java android sharedpreferences retrofit2 request-headers
2个回答
2
投票

我完全不明白这是多么令人惊讶。你的RetrofitClient是一个容易混淆(并且可以说是写得很糟糕)的单身人士。让我们来看看这会失败的典型情况。

您使用之前保存的令牌启动应用。起初一切正常。在某些时候,你打电话给RetrofitClient.getClient(token),所有请求都成功。一段时间后,服务器使令牌无效。您可能会从服务器收到403响应,再次登录屏幕并在SharedPreferences中更新您的令牌。这是你的问题开始的地方。虽然你正确地保存了你的新标记,但你的RetrofitClient会做单身人所做的事情并继续返回存储在private static Retrofit retrofit文件中的第一个实例。

一个快速的解决方法是为RetrofitClient添加一个invalidate方法。就像是。

public static void invalidate() {
  this.retrofit = null;
}

当您收到403响应或退出时,请调用它。

PS:请在if (retrofit==null) {方法的开头移动以下行getClient。每次有人打电话给getClient时都无需创建新的okHttp客户端,这只是浪费。


0
投票

您可以在网络请求发生之前编写拦截器以执行每次。将新文件创建为Header Interceptor

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());
© www.soinside.com 2019 - 2024. All rights reserved.