信道重連設計

需求概述


在現今的客戶端和服務端端的網絡交互流程中,已經實現了信道重連的功能。但目前各客戶端針對重連的實現細節並不完全統一,而在某些使用場景下,也沒有達到當初設計信道重連機制的需求。因此需要重新設計整理實現方案,保證各平臺的統一和功能的完備。

功能需求


我們需要實現以下需求:

  • 信道重連的請求由客戶端發起,客戶端需要定義規則來判斷何時發起重連請求;
  • 服務器需要在信道重連的請求響應中返回密鑰有效期,以此來作爲信道重連的最小時間間隔;
  • 所有通過信道傳輸的網絡請求,在請求過程中都需要判斷信道是否重連;
  • 客戶端需要增加配置是否禁用信道重連功能。

設計


以下說明的網絡請求,未經特殊說明的,都指經過信道傳輸的網絡請求,包括但不限於:

  • luahttp接口發出的請求;
  • js http接口發出的請求;
  • 離線更新及通過信道下載發出的請求;
  • 開發模式請求ewp服務器資源的請求;
  • 控件屬性或樣式中需要去ewp服務器請求資源的請求。

信道重連邏輯


  • 在信道握手請求中,若EWP端有配置信道重連時間,則將其值(單位秒)作爲信道重連的時間間隔,以X-Emp-CipherExpiry header的形式,返回給客戶端;
  • 客戶端在接收到EWP端的網絡響應時,解析header,如遇X-Emp-CipherExpiry字段,將其值保存,後續以此計算信道重連的時間戳;
  • 客戶端在所有通過信道傳輸的網絡請求發起前,先判斷當前系統時間是否大於信道重連的時間戳。如需要信道重連,則重新走握手流程,並在請求中加上X-Emp-Rehandshake header,值爲1;
  • EWP端在握手流程中需獲取X-Emp-Rehandshake header,若值爲1,則在握手成功後返回ok,否則與正常流程一致,返回app初始化頁面;
  • 爲保證安全,客戶端在信道重連的請求響應中判斷是否重連成功,若重連失敗,則取消後續請求,並提示網絡錯誤。其中網絡錯誤信息可配置。
  • 客戶端增加配置項是否禁用信道重連功能,該配置關閉時,不走信道重連流程。

信道重連時間戳的計算方法


  • 客戶端拿到服務器返回的X-Emp-CipherExpiry字段值後,先將其與當前系統時間相加,計算得出一個信道超時時間戳。
  • 在後續的網絡請求響應成功後,取當前系統時間與本地存儲的X-Emp-CipherExpiry字段值相加,得出新的信道超時時間戳;若請求響應失敗,無須更新時間戳。

關於併發請求的說明


由於產品的網絡請求大多爲異步請求,存在併發訪問ewp的情況。那麼很可能出現這種場景:

  1. 請求A發現信道超時,請求ewp服務器重連信道;
  2. 在A重連信道請求尚未返回時,出現併發請求B;
  3. 請求B發現信道超時,也請求ewp服務器重連信道。

這樣就造成冗餘重連信道的現象發生。

爲此規定,當某個網絡請求開啓信道重連請求時,後續觸發的網絡請求必須等待此信道重連結束後,方可繼續執行後續操作。若信道重連成功,等待的網絡請求繼續發出;若信道重連失敗,取消所有等待的網絡請求。

簡單的實現


/** 信道超時時間,非0情況下,當前時間大於此時間時,信道超時重連 */
    private static long mRehandshakeTime = 0L;
    /** 服務器返回超時時間 */
    private static long mInterval = 0L;
    /** 信道是否重連的標記 */
    private static String mRehandshake = "false";
    /** 信道重連是否成功的的標記 */
    private static String mRehandshakeSuccess = "true";
    /** 1.4 信道是否爲密文傳輸   默認true */
    private boolean mIsEncryptedTrans = true;
    /** 存放CryptoHttpManager的隊列 */
    private static ArrayList<CryptoHttpManager> mList = new ArrayList<CryptoHttpManager>();
    /** 標記是否取消後續請求。 */
    public  boolean mCancel = false;
    /** 是否重連的標記 */
    private  boolean mIsRehandshake = false;

if(!mIsRehandshake){
                    synchronized(mList){
                        if( EMPConfig.newInstance().isTlsReconnectAble() && "true".equals(mRehandshake)){
                            mList.add(this);
                            mList.wait();
                        }
                    }
                //取消後續請求返回null
                if(mCancel){
                    return resultObj;
                }
                synchronized (mRehandshake) {
                    // 請求之前首先判斷信道是否需要重建
                    if (EMPConfig.newInstance().isTlsReconnectAble() && "false".equals(mRehandshake)
                                && mRehandshakeTime != 0L && System.currentTimeMillis() > mRehandshakeTime) {
                                    mRehandshake = "true";
                                    try{
                                            //信道重連
                                            new ClientHello();
                                            // 信道重連結束後更新成功標記
                                            mRehandshakeSuccess = "true";
                                    }catch (HttpResponseException ex) {
                                        //信道重連失敗後更新標記
                                        mRehandshakeSuccess = "false";
                                        //信道重連失敗,則依次取消請求
                                        Iterator<CryptoHttpManager> iterator = mList.iterator();
                                        while(iterator.hasNext()){
                                            iterator.next().setCancel(true);
                                        }
                                        throw ex;
                                    }finally{
                                        //信道重連失敗後更新標記
                                        mRehandshake = "false";
                                        synchronized(mList){
                                            mList.notifyAll();
                                            mList.clear();
                                        }
                                    }
                        }
                }
            }
            if("false".equals(mRehandshakeSuccess)){
                return resultObj;
            }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章