最近公司在改造接口的請求的驗證,以前是登錄後返回一個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);
}
}
複製代碼
後記:多試試、多看看、多想一想,問題總會解決的;關於參考博客,我也不知道是哪一篇了,十分感謝;若有紕漏,不吝賜教!