Ⅰ rxjava+retrofit 請求網路為什麼拋出數組越界異常
rxjava+retrofit 請求網路為什麼拋出數組越界異常主線程默認有Runloop。當自己啟動一個線程,如果只是用於處理單一的事件,則該線程在執行完之後就退出了。所以當我們需要讓該線程監聽某項事務時,就得讓線程一直不退出,runloop就是這么一個循環,沒有事件的時候,一直卡著,有事件來臨了,執行其對應的函數。RunLoop,正如其名所示,是線程進入和被線程用來相應事件以及調用事件處理函數的地方.需要在代碼中使用控制語句實現RunLoop的循環,也就是說,需要代碼提供while或者for循環來驅動RunLoop.在這個循環中,使用一個runLoop對象[NSRunloop currentRunloop]執行接收消息,調用對應的處理函數.rxjava+retrofit 請求網路為什麼拋出數組越界異常
Ⅱ retrofit + okhttp 怎麼攔截伺服器返回的error信息
"解決方法:
1,如果安裝密碼保護系統需要找維護人員開啟
2,伺服器負載需要等伺服器正常時才能登陸
3,網路不穩定需要重啟電腦
4,代理出現問題,先找到電腦中的工具選項(ie瀏覽器上)。
點擊Ieternet選項。
選中高級選項。
將「通過代理連接使用 HTTP 1.1」前面的勾勾去掉,然後重新登錄游戲即可。
出現的原因:
1,如果是在網吧,有可能是網吧安裝密碼保護系統
2,伺服器負載
3,網路不穩定
4,代理出現問題
"
Ⅲ OkHTTP、Retrofit 中文亂碼解決方法
出現亂碼的根本原因是客戶端、服務端兩端編碼格式不一致導致的。
客戶端:多數情況下,客戶端的編碼格式是 UTF-8。
服務端:服務端會根據不同的請求方法使用不同的編碼格式。如:請求方法為 POST 時,編碼格式為 UTF-8;請求方法為 GET 時,編碼格式為 ISO8859-1。
當請求方法為 POST 時,客戶端和服務端兩邊的編碼格式一致,所以不存在亂碼問題。因此此處著重看下如何解決當請求方法為 GET 時的亂碼問題。
解決方法倒也簡單,只不過需要客戶端和服務端配合:
在向 URL 添加參數之前,先對目標參數進行兩次 encode,如 UTF-8:
伺服器在收到數據之後,只需將數據進行一次跟客戶端編碼格式一樣的 decode,如 UTF-8:
這樣處理之後,兩邊就不會再出現亂碼了。
通過上面的分析可知,亂碼產生的主要原因是客戶端、伺服器兩邊編碼不一致造成的,即發送 GET 請求時,客戶端使用的是 UTF-8 編碼格式對 URL 中的參數進行編碼,而伺服器在接收數據的時候,使用的是 ISO8859-1(解析 POST 請求時,伺服器使用的編碼格式是 UTF-8 編碼格式)編碼格式對 URL 中的參數進行解碼。
ISO8859-1 跟 ASCII 碼一樣,都是單位元組編碼,ISO8859-1 是從 ASCII 擴展而來的。ISO8859-1 將 ASCII 一個位元組中剩餘的最後一位用了起來,也就是說,它比 ASCII 多了 128 個字元。另外,因為 ISO8859-1 是從 ASCII 擴展而來的,所以,ISO8859-1 兼容 ASCII。
原數據:
客戶端第一次編碼,URLDecoder.decode(username, "UTF-8") 編碼之後:
客戶端第二次編碼,URLDecoder.decode(username, "UTF-8") 編碼之後:
客戶端發出的 URL:
伺服器接收的 URL:
伺服器第一次解碼,伺服器接收到 GET 請求之後,默認會用 ISO8859-1 編碼格式解碼,解碼之後得到:
需要注意的是,伺服器用 ISO8859-1 編碼格式解碼 URL 中的參數是自動完成的。
因為客戶端第一次用 URLDecoder.decode(username, "UTF-8") 編碼 URL 中參數之後,得到的是 ASCII 碼,且 UTF-8 和 ISO8859-1 對 ASCII 的編碼結果是一致的,所以,客戶端第二次用 URLDecoder.decode(username, "UTF-8") 之後的結果可以直接用 ISO8859-1 編碼格式解碼。
由於伺服器解碼之後的 URL 中的參數是用 UTF-8 編碼格式編碼的,所以,此時需要伺服器再用 UTF-8 編碼格式解碼一次。
伺服器第二次解碼,伺服器用 UTF-8 編碼格式解碼之後得到:
如果客戶端程序員沒有顯式用 UTF-8 編碼格式編碼 URL 中的參數,服務端要如何處理才能獲取到原數據?
首先,分析下如果客戶端沒有用 UTF-8 編碼格式編碼 URL 中的參數,程序是如何執行的:
網路請求框架會對 URL 中的參數進行一次 UTF-8 編碼:
伺服器會對 URL 中的參數進行一次 ISO8859-1 編碼:
明白了執行流程之後,如何解決自然也就顯而易見了:
先轉回 ISO8859-1 解碼(decode)之前的結果,再轉會 UTF-8 編碼(encode)之前的結果。
具體操作步驟:
因為 URL 中的參數經 UTF-8 編碼格式編碼之後得到的結果在 ISO8859-1 字元集可能一樣也可能根本表示不了,這也是為什麼 ASCII 碼經 UTF-8 編碼格式編碼之後的結果可以用 ISO8859-1 編碼格式解碼。如,在 Unicode 字元集中,第 20013 個字元是「中」,而在 ISO8859-1 字元集中,一共才有 256 個字元。字元「中」經 UTF-8 編碼之後的結果再經 ISO8859-1 解碼,無論如何也得不到正確答案的。
Ⅳ Android Okhttp/Retrofit網路請求加解密實現方案
比較安全的方案應該是AES+RSA的加密方式。具體如下圖所示。
為什麼要這樣做呢?
1、RSA是非對稱加密,公鑰和私鑰分開,且公鑰可以公開,很適合網路數據傳輸場景。但RSA加密比較慢,據說比AES慢100倍,且對加密的數據長度也有限制。
2、AES是對稱加密,加密速度快,安全性高,但密鑰的保存是個問題,在網路數據傳輸的場景就很容易由於密鑰泄露造成安全隱患
3、所以,AES+RSA結合才更好,AES加密數據,且密鑰隨機生成,RSA用對方(伺服器)的公鑰加密隨機生成的AES密鑰。傳輸時要把密文,加密的AES密鑰和自己的公鑰傳給對方(伺服器)。對方(伺服器)接到數據後,用自己的私鑰解密AES密鑰,再拿AES密鑰解密數據得到明文。這樣就綜合了兩種加密體系的優點。
4、除上面說的外,還可以加簽名,即對傳輸的數據(加密前)先做個哈希,然後用自己的RSA私鑰對哈希簽名(對方拿到自己的公鑰可以驗簽),這樣可以驗證傳輸內容有沒有被修改過。
就java來說,加密的輸入和輸出都是位元組數組類型的,也就是二進制數據,網路傳輸或本地保存都需要重新編碼為字元串。推薦使用Base64。Android 有自帶的Base64實現,flag要選Base64.NO_WRAP,不然末尾會有換行影響服務端解碼。
Android中Base64加密
總而言之,這些不同語言都有實現庫,調用即可,關鍵是參數要一致,具體還需要和後台聯調一下。
rsa加解密的內容超長的問題解決
現在說到網路框架,應該毫無疑問是Retrofit了。上面說的加密方案說到底還是要在網路請求框架內加上,怎麼做入侵最小,怎麼做最方便才是重點。
1、坑定不能直接在介面調用層做加密,加參數,這樣每個介面都要修改,這是不可能的。
2、ConverterFactory處理,這也是網上可以搜到的很多文章的寫法,但我覺得還是有入侵。而且有點麻煩。
3、OkHttp添加攔截器,這種方法入侵最小(可以說沒有),實現呢也非常優雅。
下面的實現,網上也找不到多少可以參考的文章,但不得不說,OkHttp的封裝和設計真的很好用,所見即所得。看下源碼,就知道該怎麼用了,連文檔都不用查。
主要注意點:
0、和介面無關的新加的數據放在請求頭里。
1、該close的要close,不然會內存泄漏。
2、新舊Request和Response要區分好,新的要替換舊的去傳遞或返回。
3、要對response.code()做處理,只有在和後台約定好的返回碼下才走解密的邏輯,具體看自己的需求,不一定都是200。
Ⅳ Retrofit的淺析 —— 針對面試
1.近兩年Retrofit非常熱門,特別是結合Rxjava運用到項目中。Retrofit一個RESTful的Http網路請求框架的封裝,內部封裝了Okhttp網路請求框架,對網路請求做了大量優化。Retrofit其最大特點就是解耦,要解耦就需要大量的設計模式,內部使用了外觀模式、構建模式、觀察者模式、動態代理模式、策略模式、適配器模式和裝飾模式等等;
實際上分析Retrofit需要熟悉Okhttp才能深入分析Retrofit,Retrofit不止使用okhttp的內核,它還封裝了CallAdapter-請求適配器:可以實現多種請求響應形式:同步方式、非同步回調方式、RxJava方式;封裝了Converter-數據轉換器:可以自己定義responseBodyConverter和requestBodyConverter,實現加密功能和各種數據格式的解析;
retrofit 結合 okhttp 的原因就是retrofit使用了代理模式,默認代理走的就是okhttp,okhttp 負責網路請求, retrofit 負責對網路的處理,包括gson解析都是封裝在retrofit裡面的,如果哪天okttp不流行了是可以切換到別的網路框架的
Retrofit(改良)框架是Square公司出品的目前非常流行的網路框架,效率高,實現簡單,運用註解和動態代理設計模式,極大的簡化了網路請求的繁瑣步驟,非常適合處理REST ful(一種風格)網路請求.目前Retrofit版本是2(可以說是Square公司之前出品okhttp的升級版)
性能好,處理快,使用簡單.(速度比Volley更快)
使用REST API非常方便
支持NIO(新的IO API,可以替代標準的Java IO API)
Retrofit默認使用okhttp處理網路請求;
默認使用Gson解析
1.在項目的build.gradle中添加依賴後一個依賴比前一個多了個Gson解析的功能,看需求,二者依賴一個即可, 一 般依賴帶Gson解析的依賴
compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
<uses-permission android:name="android.permission.INTERNET" />
@GET GET網路請求方式
@POST POST網路請求方式
@Headers 頭信息參數
@Path 路徑參數.替換url地址中 "{" 和 "}"所包括的部分
@Query 查詢參數.將在url地址中追加類似"page = 1"的字元串,形成提交給伺服器端的請求參數
@QueryMap 查詢參數集合.在url地址中追加類似"type = text & count = 30 & page = 1 " 的字元串
@FormUrlEncoded 對表單域中填寫內存進行編碼處理,避免亂碼
@Field 指定from表單域中每個控制項的name及相應數值
@FieldMap 表單域集合
@Multipart Post提交分塊請求.如果上傳文件,必須指定Multipart
@Part Post提交分塊請求
@Body Post提交分塊請求
1.設置請求方式是註解的形式
2.介面拼接字元串更靈活
3.非同步響應回調方法在主線程
/**
* 作用:GET請求最簡單的寫法,無Path參數和Query參數
* article/list/latest?page=%d實際是Constant下的URL_LATEST地址
* @GET()里的東西是要拼接的網址,注意直接把page=1了
*/
@GET("article/list/latest?page=1")
Call<ResponseBody> getLatestJsonString();
/**
* 其中註解中的變數用{ 變數名自定義 } 在方法參數中
* 格式:@Path("上面定義的變數名") 類型 定義的變數名 作用:替換url地址中"{"和"}"所包括的部分
* 格式:@Query("參數名") 類型 定義的參數名 作用:會拼接在URL的最後部分,類似追加了"page = 1"的字元串,最後提交給伺服器
*/
@GET("article/list/{type}?")
Call<QiushiModel> getInfoList(@Path("type") String type, @Query("page") int page);
/**
* @QueryMap參數將在url地址中追加類似"type = text & count = 30 & page = 1 " 的字元串
*/
@GET("web/LoginServlet")
Call<ResponseBody> getRegInfo(@QueryMap Map<String, String> map);
/**
* 靜態的URL地址
*/
@GET("http://img.265g.com/userup/1201/201201071126534773.jpg")
Call<ResponseBody> getNetworkData();
/////////////////////////////////////////////////// Post ////////////////////////////////////////////////
/**
* 作用:post網路請求,向伺服器提交表單域數據
* @FormUrlEncoded:解決編碼亂碼問題,
*/
@FormUrlEncoded
@POST("web/LoginServlet")
Call<ResponseBody> postFormFields(@Field("username") String username,@Field("password") String password);
/**
* 作用:post網路請求,向伺服器提交表單域數據
* @FormUrlEncoded:解決編碼亂碼問題,
*/
@FormUrlEncoded
@POST("web/LoginServlet")
Call<ResponseBody> postFormFieldMap(@FieldMap Map<String , String> map);
/**
* 上傳單個文件,必須加上 @Multipart 註解
*/
@Multipart
@POST("web/UploadServlet")
Call<ResponseBody> postUploadFile(@Part("uploadfile\";filename=\"myuploadimg.png") RequestBody requestBody);
Retrofit2中Base Url與@Url不是簡單的組合,而是和<a href = "...">的處理方式一樣
提示:Base URL: 以"/"結尾 @Url:不要以"/"開頭
Ⅵ Retrofit 源碼分析
現代Android開發中,Retrofit是主流的網路請求框架,內部封裝OkHttp發起請求,也是聲明式Http客戶端,使用介面 + 註解的方式在介面中編寫請求方法。
先看下常規Retrofit的使用吧,也是通過入口API來看源碼的一種好方法。
我們先來看不添加Convert轉換器的方式,這種方式只能設置返回值中的泛型為ResponseBody,拿到的數據只能是Json字元串,而轉換模型的操作需要我們自己做,當然如果是添加了轉換器,則可以直接寫模型的泛型了
從簡單使用來看,我們發現以下幾點
簡單來講,就是把Retrofit的構造方法私有,只能通過內部的Builder內部類的實例創建,所以我們對Retrofit的配置,都是配置到Retrofit內的Builder類後,再通過它的build方法,創建Retrofit實例。
在Builder的構造方法中,調用了Platform類的get方法,這個類是適配調用平台的,因為Retrofit的介面請求在子線程請求,而介面響應的回調方法,是可以在Android的主線程中回調的,這就肯定會涉及到Handler,而Retrofit也支持在鴻蒙上使用,這時就需要拓展Platfrom類來實現
可以看到,如果在Android平台運行,則返回的是Android實現類,該類復寫了 defaultCallbackExecutor() 方法,返回 MainThreadExecutor 實例,這個Executor其實是線程池介面,只有一個 execute() 方法, MainThreadExecutor 類復寫了 execute() 方法,通過Handler把傳進來的Runnable轉發到主線程進行回調
Http介面的實現,是通過 create() 方法創建的,內部使用的是JDK的動態代理,當我們調用代理類的方法時,會回調 InvocationHandler 的 invoke() 方法
在 InvocationHandler 類的 invoke() 方法中,如果調用的是Object類的方法,直接調用,如果是Java8的默認方法,直接調用。最後就是普通的API方法,則調用 loadServiceMethod() ,這個方法的作用是解析API方法,並緩存到一個Map中,下次調用是直接復用的,最終是需要返回一個不為null的 ServiceMethod 實例,再調用它的 invoke() 執行方法調用
loadServiceMethod () 中,如果沒有命中緩存,則通過 ServiceMethod.parseAnnotations() ,解析方法註解,返回 ServiceMethod 實例,再緩存起來
其中, ServiceMethod 是一個抽象類
RequestFactory 類也是一個Builder建造者模式,只是它是通過 Builder 類拆解 Method 對象,再通過 build 方法開始解析方法上的註解
註解分2種,分別是: 方法級的註解 和 方法形參上的註解 , 方法級的註解 是 @GET 、 @POST 這種作用於方法上的註解,而 方法形參上的註解 則是 @Path 、 @Field 這種作用於形參上的註解
最後返回 RequestFactory 實例,最後調用 HttpServiceMethod.parseAnnotations() ,進行返回值適配和轉換器
ServiceMethod 是一個抽象類,通過 ServiceMethod.parseAnnotations() 靜態方法,會返回其子類 HttpServiceMethod ,子類的創建則是通過 HttpServiceMethod.parseAnnotations() 創建
通過解析方法的返回值,調用 createCallAdapter() ,查找能適配返回值的 CallAdapter ,再調用 createResponseConverter() 查找對應的 Converter 轉換器
發現, HttpServiceMethod 也是一個抽象類,它在 ServiceMethod 的 invoke() 基礎上,調用了一個 adapt() 抽象方法,其子類 CallAdapted ,復寫了該方法,最終 invoke() 方法是通過 CallAdapter 來進行處理
查找適配器的工作,發現是通過 Retrofit 實例 callAdapter() 方法,for循環查找注冊的適配器,如果沒有找到則拋異常,這實際上是策略模式的應用
CallAdapter.Factory 是 CallAdapter 的工廠類,每次發起請求,都是通過 CallAdapter.Factory 創建一個 CallAdapter 進行適配工作
主要方法是 Factory.get() ,創建 CallAdapter ,而 CallAdapter 的主要方法是 adapt ,該方法對Call類進行適配,以及 responseType() ,該方法返回該適配器能處理的返回值類型中的泛型Type
在 Retrofit 構建時,就添加了一個默認的 CallAdapter.Factory 實例,它就是 DefaultCallAdapterFactory ,所以就是我們什麼都不配置,默認找到的 CallAdapter.Factory 就是 DefaultCallAdapterFactory
發現這個工廠類,在 get() 方法中,創建了一個 CallAdapter 的匿名內部類, responseType() 返回了Call中的泛型Type,然後 adapt() 方法創建了一個 ExecutorCallbackCall 類,該類實現了 Call 介面
它其實是一個裝飾器,包裝了當前請求的 Call 類實例,並把 enqueue() 方法中的回調通過 callbackExecutor 做了調用包裝,這個 callbackExecutor 就是 Platform 類中的 MainThreadExecutor 實例,所以就是這里來做回調的主線程回調的!
CallAdapter 查找完後,再查找 Converter 轉換器,它的邏輯和上面查找 CallAdapter 很類似,都是在 Retrofit 的實例上找, Converter 也有一個 Factory 工廠類
同樣,每次請求則創建都通過 Factory 創建一個 Converter 實例, Converter 有2種
responseBodyConverter() ,把ResponseBody轉換為Type類型的模型(請求響應回來時調用),就是負責把介面響應的json數據,轉換為對應的模型類
requestBodyConverter() ,把Type模型轉換為RequestBody,就是application/json這種類型的請求,把模型類轉換為Json字元串,然後把Json字元串設置到RequestBody中
在 Retrofit實例 創建中,也默認添加了一個轉換器工廠,它就是 BuiltInConverters
Ⅶ android 網路請求Retrofit+Rxjava報錯
檢查項目依賴的retrofit和rxjava版本是否一致,大多數java.lang.IllegalStateException: Fatal Exception thrown on Scheler.Worker thread.都是由於這個問題造成的
2. compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
compile 'com.squareup.retrofit2:retrofit:2.1.0'
把版本調成一樣的,重新gradle一下應該就闊以了
Ⅷ retrofit 請求偶爾出現404 怎麼辦
1.首先定義帶泛型的返回結果,RetrofitAPI的原生結果映射為這種形式:classResult{StringResultMessage;intResultCode;TData;}2.處理錯誤的方法和@朱詩雄前輩方法差不多,放到作為靜態方法放到RetroUtil里,這里ApiException為自己定義的一個異常,放入錯誤碼和錯誤信息(錯誤碼不止一個):staticObservableflatResult(Resultresult){returnObservable.create(subscriber->{switch(result.ResultCode){caseConstants.SUCCESS_CODE:subscriber.onNext(result.Data);break;caseConstants.ERROR_CODE:subscriber.onError(newApiException(result.ResultCode,result.ResultMessage);break;default://}subscriber.onCompleted();}});}3.在API包裝類對於上述Result格式的返回結果,統一調用flatMap(RetroUtil::flatResult)後的API。這樣每個API的返回結果就是Observable的形式並且在errorHandler中統一處理錯誤了。//介面方法Observable>getUserInfo();//包裝後的方法ObservablegetUserInfo(){returnmApi.getUserInfo.flatMap(RetroUtil::flatResult);}//調用時apiWrapper.getUserInfo().subscrible(user->{//處理正常邏輯},error->{//處理錯誤邏輯和異常,這里封裝時通常也會統一處理,//提供一個默認的Action1參數,彈出//throwable的message列印日誌等});
Ⅸ Retrofit2.0+RxJava網路請求異常統一處理
本文內容是基於RxJava 2.0及Retrofit 2.1分析的。參考了 Rxjava +Retrofit 你需要掌握的幾個技巧,Retrofit緩存,統一對有無網路處理, 異常處理,返回結果問題
下面列出具體添加的依賴。
以下這些錯誤,都是在網路請求中經常見的。我們可以通過Toast彈出消息通知用戶具體的異常以及載入對應的UI界面。除此之外,通過具體的異常信息,方便我們及時的排查項目中的BUG。
那麼問題就來了,我們如何判斷異常的類型?
這就要從伺服器返回的數據格式說起了。
我們一般請求的返回都是像下面這樣
伺服器端返回數據約定俗稱就是大概以上的格式。可能具體的code碼表示的含義不一樣,這個可以與伺服器端人員交流,靈活變化。
關於Retrofit的基本配置就不再講述了,這里具體講解如何對伺服器返回數據封裝以及使用RxJava對錯誤信息處理。
封裝返回數據
對於上述的伺服器返回數據我們要對code做出一些判斷,code不為200(假設200表示請求網路成功)就拋出異常。所以我們新建一個BaseResponse類,對應上面的數據結構。
這算是所有實體的一個基類,data可以為任何數據類型。
然後要對返回結果進行預處理,新建一個ExceptionHandle。預處理無非就是當根據返回數據BaseResponse的isOk()方法判斷為是否為true,若為true則正常處理,否則拋出異常讓ExceptionHandle進一步處理,判斷異常為何種異常。我們先跳過前面的邏輯,先了解如何判斷是何種異常?
判斷異常類型
詳細可看源碼,下面會貼出地址。
通過ExceptionHandle.handleException(Throwable e) 即可返回一個異常,並攜帶具體異常類型信息。
現在我們已經知道了如何判斷是否產生以上以及如何判斷異常類型。接下來需要解決地就是如何把異常傳遞給Observer的onError(Throwable e)去處理異常。
在進行異常傳遞的過程中,第一步我們先要判斷伺服器返回的數據是否是異常,如果不是異常則返回data數據,如果是異常則拋出異常。這個時候就包含了一個數據轉換的過程即把BaseResponse對象轉換成data類型的對象,所以需要map()操作符。
其中HandleFuc實現了 Function<BaseResponse<T>, T> 介面
如果不出現異常則不會走第二步。如果出現異常,則需要進行第二步,即對異常進行判斷,然後將ExceptionHandle.handleException(Throwable e) 返回的異常傳入onError()中處理。
重點來了:當產生異常時,應該終止對onNext()方法的調用並調用onError()方法。如果不繼續處理,僅通過以上步驟,雖然會調用onError()方法,但是沒有對異常進行判斷,並且沒有取消onNext()方法。那麼有沒有一個好的方法,可以即取消onNext()方法,又能在其中實現異常判斷的執行,並且會調用onError()方法?
如此強大的RxJava自然有這樣的方法了, onErrorResumeNext() 就能實現這個要求。對於 onErrorResumeNext() ,可以簡單理解為:當發生錯誤的時候,由另外一個Observable來代替當前的Observable並繼續發射數據。
onErrorResumeNext() 中傳入的參數可以是一個Function介面。這樣,我們可以在Function中生成一個Observable,該Observable執行異常判斷的邏輯,並調用onError()方法。
具體實現如下:
至此,我們便實現了異常判斷與傳遞的邏輯。這樣我們就可以在onError()方法中提取具體的異常狀態信息,進行相應的處理。
大概流程是:map()進行數據類型轉換,並檢測異常。如果正常,返回data類型的數據。如果不正常,onErrorResumeNext()判斷異常類型並傳遞異常
上述情況關閉了網路。當發起網路請求,沒有網路則拋出異常,然後檢測出具體異常,Toast提示異常類型,用戶便知道是什麼地方出錯了。
demo參考地址: https://github.com/maioo/RetrofitRxJavaException
Ⅹ Android上使用retrofit+okhttp時token失效的處理方案
提前聲明,以下提到的方案並沒有去驗證過可行性,只是記錄一下,未來需要用到的時候,在仔細驗證一下。
一般情況下,各個公司的移動端關於登錄令牌(token)的設定都各不相同。
可先參考這個鏈接: https://www.hu.com/question/30267006
了解一下,本文大概想說什麼。
有些公司服務端是按照oauth設計,比較標准規范,但是有些公司有自己的特定業務,未完全按照oauth來設計。基於本公司的業務邏輯,考慮了一下登錄的邏輯以及token的設計。
思路如下:
token即驗證令牌,每次請求都帶上,refreshToken用來刷新token的,每次請求可以不帶上,但是要放在移動端保存。
1.通過username,password獲取token和refreshToken
2.token的有效期為2小時,refreshToken的有效期為15天
3.如果伺服器端判斷token過期,而refreshToken未過期,就返回錯誤碼給客戶端,則客戶端通過一個特定的介面傳入refreshToken參數獲取新的token和refreshToken
4.如果連續15天未使用app或者用戶修改了密碼,則表示refreshToken過期了,則跳到登錄界面,重新登錄獲取token和refreshToken
基於上面的思路,如果服務端走rest風格,移動端(Android)採用retrofit(v2.0+)+okhttp(v2.7.0+)網路請求框架。那麼當token過期了,Android端應該如何處理呢?
通過okhttp提供的Authenticator介面,相關資料 點擊這里 ,但是查看okhttp的源碼會發現,只有返回HTTP的狀態碼為401時,才會使用Authenticator介面,如果服務端設計規范,可以嘗試如下方法。
實現Authenticator介面
然後給添加給OkHttpClient
第一種方案就這樣了。
但是,萬事不會盡如人意,如果服務端在token過期的時候,不給返回401的HTTP狀態碼,而是返回如下類型的數據,叫你根據code判斷。
這里要清楚HTTP狀態碼是指200,404,401這些,而上面的數據中的code是自定義的。如果在token過期時,服務端返回的是如上類型的數據,那麼第一種方案就行不通。
通過okhttp的攔截器,okhttp 2.2.0 以後提供了攔截器的功能,相關介紹 點擊這里
然後給okhttp設置攔截器
第二種方案的思路是通過攔截返回的數據,判斷token是否過期,如果過期則進行一次刷新token的操作。
上面2種方案都沒有進行實際驗證過,希望以後有機會能驗證。
完。。。