最近公司在改造接口的请求的验证,以前是登录后返回一个token,在请求的时候动态添加到header中,以此来验证身份,当返回401直接去从新登陆;如今登陆返回token和refreshToken两个参数,拿token去添加header,当返回401时并不直接去登陆而是拿refreshToken去请求一个接口,刷新获得新的token和refreshToken,拿到新的token再去请求当前返回401的接口,若是此时返回410则是真正的过时才须要去登陆。json
Response response = chain.proceed(builder.build());
ResponseBody responseBody = response.body();
BufferedSource source = responseBody.source();
source.request(Long.MAX_VALUE);
Buffer buffer = source.buffer();
Charset charset = UTF8;
MediaType contentType = responseBody.contentType();
if (contentType != null) {
charset = contentType.charset(UTF8);
}
//获取响应体的字符串
String bodyString = buffer.clone().readString(charset);
CustomResponse customResponse = new Gson().fromJson(bodyString, CustomResponse.class);
String code = customResponse.getCode();//后台的返回码
String msg = customResponse.getMsg();
if ("401".equals(code)) {
//todo 当返回401时去刷新token
}
//不然正常返回 response
复制代码
Map<String, String> map = new ArrayMap<>();
map.put("refreshToken", refreshToken);//这是咱们在登陆成功后返回的refreshToken,专门用于刷新操做的
RequestBody body = NetworkUtils.setBody(map);
Call<CustomResponse<Map<String, String>>> call = RetrofitUtils.provideClientApi().refreshToken(body);
CustomResponse refreshResponse = call.execute().body();
Map<String, String> mapToken = (Map<String, String>) refreshResponse.getData();
String refreshCode = refreshResponse.getCode();
复制代码
刷新成功后有两种操做,若是返回200,拿到新的token去从新请求当前报401的接口,若是返回410(固然也能够是110,由于这是咋们和后台小伙伴约定的这个时候就是token真正的过时了,直接去从新登陆。bash
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();//这里的request只是为了拿到请求的url和参数,下面要从新生成request(builder.build())
Request.Builder builder = request.newBuilder()
.addHeader("Content-Type", "application/json; charset=UTF-8")
.addHeader("Authorization", newToken);
//注意:chain.proceed(这里必定不能是拿到的request,而是builder.build())
return chain.proceed(builder.build());
}
复制代码
好了,完成并发
synchronized (mContext) {
Map<String, String> map = new ArrayMap<>();
map.put("refreshToken", refreshToken);//这是咱们在登陆成功后返回的refreshToken,专门用于刷新操做的
RequestBody body = NetworkUtils.setBody(map);
Call<CustomResponse<Map<String, String>>> call = RetrofitUtils.provideClientApi().refreshToken(body);
CustomResponse refreshResponse = call.execute().body();
Map<String, String> mapToken = (Map<String, String>) refreshResponse.getData();
String refreshCode = refreshResponse.getCode();
}
复制代码
其实仔细想一想,若是咱们已经刷新过token了,那就直接拿最新的newToken去从新请求当前接口就行了,咱们拿到最新的token确定是须要保持成全局的,而咱们全部的请求是异步的,那就能够拿到每次的request,这意味着什么?咱们就能够拿到header,那以前过时的token就有了;两者一对比,同样则说明尚未刷新过token,那就先去刷新token,不同说明已经有接口刷新过了直接拿最新newToken的去从新请求就行了。(就是一个判断就不贴代码了【偷笑】)app
String oldToken = request.header("Authorization");
String oldToken = request.headers().get("Authorization");
复制代码
Request.Builder builder = request.newBuilder()
.addHeader("Content-Type", "application/json; charset=UTF-8")
.addHeader("Authorization", newToken);
复制代码
String oldToken = response.request().headers().get("Authorization");
复制代码
if ("401".equals(code)) {
synchronized (mContext) {
refreshToken = "获取最新的refreshToken"
token = "获取最新的token"
String oldToken = response.request().headers().get("Authorization");
/**
* 当前请求中的jwt和本地最新的是否同样:
* 一、同样则说明没有进行刷新token操做不进入此 if
* 二、不同则说明已经刷新过token操做了,进入此 if 拿最新的token直接从新发起当前的请求
*/
if (!token.equals(oldToken)) {
Request.Builder newBuilder = getBuilder(chain.request(), token);
return getNewResponse(chain, newBuilder);
}
Map<String, String> mapToken = refreshMapToken(refreshToken);
String newToken = mapToken.get("token");
String newRefreshToken = mapToken.get("refreshToken");
MyApplication.setToken(newToken);//设置为全局常量
"此处还须要的一个操做是把两者都保存到本地,否则下次登陆就没了"
Request.Builder newBuilder = getBuilder(chain.request(), newToken);
return getNewResponse(chain, newBuilder);
}
}
复制代码
后记:多试试、多看看、多想一想,问题总会解决的;关于参考博客,我也不知道是哪一篇了,十分感谢;若有纰漏,不吝赐教!