前言
在app實(shí)際請(qǐng)求服務(wù)器接口的過程中常柄,經(jīng)常會(huì)遇到session過期的情況忌堂,這時(shí)候需要我們重新登錄刷新session。
期初實(shí)現(xiàn)的方案是,發(fā)現(xiàn)session過期需要登錄時(shí)寝并,直接跳轉(zhuǎn)到登錄界面鞭衩,登陸后跳轉(zhuǎn)首頁苛白。
但更合理的情形是一旦發(fā)現(xiàn)session過期焰檩,直接調(diào)用登錄接口刷新session,之后繼續(xù)原來的業(yè)務(wù)膘婶,即在此請(qǐng)求原來的業(yè)務(wù)接口缺前。
本文就將針對(duì)使用OKHttp3的底層網(wǎng)路框架的情形,說一下如何實(shí)現(xiàn)session過期的統(tǒng)一處理悬襟。
有興趣的同學(xué)可以加入學(xué)習(xí)小組QQ群: 193765960做進(jìn)一步的討論衅码。
版權(quán)歸作者所有,轉(zhuǎn)發(fā)請(qǐng)注明出處:http://www.reibang.com/u/d43d948bef39
1. 總體方案:攔截器
1)在網(wǎng)絡(luò)請(qǐng)求的底層OKhttp層設(shè)置攔截器脊岳,攔截網(wǎng)絡(luò)請(qǐng)求和響應(yīng)數(shù)據(jù)逝段。
2)分析響應(yīng)數(shù)據(jù)垛玻,根據(jù)響應(yīng)的狀態(tài)判斷是否發(fā)生session過期。
3)如果沒有過期奶躯,則正常返回響應(yīng)數(shù)據(jù)帚桩。
4)如果發(fā)生session過期,則取消當(dāng)前響應(yīng)數(shù)據(jù)嘹黔,生成刷新session的請(qǐng)求(一般是登錄請(qǐng)求)账嚎。
5)如果session刷新成功,根據(jù)原來業(yè)務(wù)的請(qǐng)求數(shù)據(jù)從新發(fā)起請(qǐng)求儡蔓。
6)如果session刷新失敗郭蕉,則返回session過期的異常響應(yīng),在上層解析該響應(yīng)后跳轉(zhuǎn)登錄界面喂江。
7)從登錄界面重新登陸后召锈,跳轉(zhuǎn)到首頁。
2. 攔截器的實(shí)現(xiàn)
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
public class SessionKeyInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request old_request = chain.request();
Response old_response = chain.proceed(old_request);
//下面這行代碼注意下获询,不要使用Gson等工具對(duì)old_response.body等直接轉(zhuǎn)化涨岁,會(huì)出問題的。
//RequestHelper: 工具類小伙伴們可以加群吉嚣,單獨(dú)找我索要
JSONObject obj = RequestHelper.response2Object(old_response);
//如果session過期梢薪,則重新登錄獲取sessionkey
if (obj != null && TextUtils.equals(obj .optString("error_code"), MyConfig.getSessionKeyErrorNumber())) {
//上層注入的請(qǐng)求MyRequest
MyRequest loginp = LoginUtils.getRequest();
if(null == loginp || loginp.size()==0){
return old_response;
}
if(null == LoginUtil.getLoginApi()){
return originalResponse;
}
Request login_request = RequestHelper.buildGetRequest(loginparam, LoginUtils.getLoginApi());
Response login_response = chain.proceed(login_request);
if (login_response.isSuccessful()) {
JSONObject obj2 = RequestHelper.response2Object(login_response);
if(obj2!= null && (TextUtils.equals(obj2.optString("error_code"), "http://api請(qǐng)求成功的狀態(tài)碼"))){
//登錄成功,執(zhí)行原始request
String sessionKey = "";
try {
sessionKey = obj2.getJSONObject("jsondata").getString("session_key");
} catch (JSONException e) {
e.printStackTrace();
}
login_response.body().close();
Map<String, Object> param = RequestHelper.parseParams(old_request);
//更新old_request的session_key等可變參數(shù)
param.put("sessionKey",sessionKey);
MyRequest request = new MyRequest ();
request.put(param);
originalRequest = RequestHelper.handler(request, old_request);
originalResponse.body().close();
return chain.proceed(old_request);
}
}
}
return old_response;
}
基于項(xiàng)目代碼安全的需要瓦戚,對(duì)以上代碼做了處理沮尿,不過大體的思路都是可用的
3. 登錄請(qǐng)求的上層注入
為了更好地適用于不同的項(xiàng)目丛塌,和后期代碼的維護(hù)较解,判斷session是否過期的判斷依據(jù)采用上層配置并注入的方式。
當(dāng)然赴邻,您也可以直接在Okhttp層寫死印衔,開發(fā)難度會(huì)簡(jiǎn)單很多,只是后期維護(hù)或者做項(xiàng)目移植時(shí)需要特別注意修改姥敛。
發(fā)起session刷新的接口請(qǐng)求參數(shù)也是同樣的處理奸焙。不再一一贅述。
4. 存在問題
長(zhǎng)時(shí)間在后臺(tái)靜默APP彤敛,數(shù)據(jù)有可能會(huì)被gc掉与帆,所以這種情況下,系統(tǒng)不會(huì)無縫的去成功刷新session并執(zhí)行目標(biāo)請(qǐng)求的業(yè)務(wù)邏輯墨榄,而是會(huì)直接啟動(dòng)登錄界面玄糟。
這個(gè)攔截器,僅僅針對(duì)了session過期的情況袄秩,其實(shí)功能邏輯具有通用性阵翎,可以考慮和業(yè)務(wù)解耦逢并,通過注入的方式支持更多異常的無縫處理。
以上郭卫。