请求中添加token
登录成功后,之后的请求一般都需要将token添加到请求头中,才能得到正确的回调结果。利用Okhttp的Interceptor可以方便的做到这一点
public class TokenInterceptor implements Interceptor {
private String token;
public TokenInterceptor(String token) {
this.token = token;
}
public void setToken(String token) {
this.token = token;
}
@Override
public @NotNull Response intercept(@NotNull Chain chain) throws IOException {
Request original = chain.request();
Request.Builder builder = original.newBuilder()
.header("token", token);
Request request = builder.build();
return chain.proceed(request);
}
}
登录成功后:
TokenInterceptor tokenInterceptor = new TokenInterceptor(token);
HttpManager.getInstance().addInterper(tokenInterceptor);
token失效后的处理
token失效后,可请求新的token后,用新token请求当前数据;或许直接跳转到登录页。 这两种方式都需要在token失效时能拦截到。
方式1:实现Authenticator接口
public class TokenAuthenticator implements Authenticator {
@Override
public Request authenticate(Proxy proxy, Response response) throws IOException {
//取出本地的refreshToken
String refreshToken = "sssgr122222222";
// 通过一个特定的接口获取新的token,此处要用到同步的retrofit请求
ApiService service = ServiceManager.getService(ApiService.class);
Call<String> call = service.refreshToken(refreshToken);
//要用retrofit的同步方式
String newToken = call.execute().body();
return response.request().newBuilder()
.header("token", newToken)
.build();
}
@Override
public Request authenticateProxy(Proxy proxy, Response response) throws IOException {
return null;
}
}
由于业务中没遇到过这种http响应401的情况,所以只是转载记录一下,大多时遇到方式2的情况,在http响应200的情况下,判断自定义状态码,反馈token失效的情况:
{"data":null,"message":"请重新登录。","status":401}
public class TokenInterceptor implements Interceptor {
private static final Charset UTF8 = Charset.forName("UTF-8");
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
// try the request
Response originalResponse = chain.proceed(request);
/**通过如下的办法曲线取到请求完成的数据
*
* 原本想通过 originalResponse.body().string()
* 去取到请求完成的数据,但是一直报错,不知道是okhttp的bug还是操作不当
*
* 然后去看了okhttp的源码,找到了这个曲线方法,取到请求完成的数据后,根据特定的判断条件去判断token过期
*/
ResponseBody responseBody = originalResponse.body();
BufferedSource source = responseBody.source();
source.request(Long.MAX_VALUE); // Buffer the entire body.
Buffer buffer = source.buffer();
Charset charset = UTF8;
MediaType contentType = responseBody.contentType();
if (contentType != null) {
charset = contentType.charset(UTF8);
}
String bodyString = buffer.clone().readString(charset);
LogUtil.debug("body---------->" + bodyString);
/***************************************/
if (response shows expired token){//根据和服务端的约定判断token过期
//取出本地的refreshToken
String refreshToken = "sssgr122222222";
// 通过一个特定的接口获取新的token,此处要用到同步的retrofit请求
ApiService service = ServiceManager.getService(ApiService.class);
Call<String> call = service.refreshToken(refreshToken);
//要用retrofit的同步方式
String newToken = call.execute().body();
// create a new request and modify it accordingly using the new token
Request newRequest = request.newBuilder().header("token", newToken)
.build();
// retry the request
originalResponse.body().close();
return chain.proceed(newRequest);
}
// otherwise just pass the original response on
return originalResponse;
}
}
OkHttpClient client = new OkHttpClient();
client.interceptors().add(new TokenInterceptor());
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASEURL)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.client(getOkHttpClient())
.build();