改造无法将新令牌设置为请求标头
Posted
技术标签:
【中文标题】改造无法将新令牌设置为请求标头【英文标题】:Retrofit unable to set new Token to Header of Requests 【发布时间】:2018-06-29 16:15:28 【问题描述】:我有一个改造客户端,它可以帮助我为我向 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);
【问题讨论】:
请显示调用 setToke/getToken 方法的代码。这一行不足以理解发生了什么。 @algrid 我在其他地方阅读了一个解决方案,但我不知道如何实现它。这就是用户所说的“这是因为您添加的拦截器在 httpClient 中仍然存在。一旦您删除了令牌(或将 null 传递给 createService() 方法,您也需要删除拦截器。” 你必须编写拦截器来附加新令牌 @IshanFernando 你能展示一段代码 sn-p 来编写拦截器吗? @LendingSquare 我添加了示例代码 【参考方案1】:我完全不明白这有多令人惊讶。您的 RetrofitClient
是一个令人困惑的(并且可以说是写得不好)的单身人士。让我们来看看这会失败的典型情况。
您使用之前保存的令牌启动您的应用程序。起初一切正常。在某些时候,您调用 RetrofitClient.getClient(token)
并且所有请求都会成功。一段时间后,服务器使令牌无效。您可能会从服务器收到 403 响应,再次启动登录屏幕并在 SharedPreferences 中更新您的令牌。这是您的问题开始的地方。尽管您正确保存了新令牌,但您的 RetrofitClient
将执行单例操作并继续返回存储在 private static Retrofit retrofit
字段中的自身的第一个实例化。
一种快速的解决方法是向您的RetrofitClient
添加一个无效方法。类似的东西。
public static void invalidate()
this.retrofit = null;
在收到 403 响应或注销时调用它。
PS:请在getClient
方法的开头移动以下行if (retrofit==null)
。新建一个okHttp客户端,白费,每次有人打电话getClient
就是浪费。
【讨论】:
非常感谢您的回答 没问题,很高兴它有帮助【参考方案2】:您可以编写拦截器在每次网络请求发生之前执行。创建新文件作为 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());
【讨论】:
先生,在这个类中context
将如何被传递?如果我没记错的话,我们必须在添加拦截器时通过 RetrofitClient 类的 HeaderInterceptor 类的构造函数传递上下文。所以每次我们调用 RetrofitClient 的静态方法 getClient() 时,我们都需要传递上下文。这个过程对吗?还是有其他方法?
是的,这就是我实施的方式。我不知道其他方式。如果我发现任何东西,我会发布它@HasanAbdullah以上是关于改造无法将新令牌设置为请求标头的主要内容,如果未能解决你的问题,请参考以下文章
在 ember-file-upload 的请求标头中添加身份验证令牌