国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

網絡請求異常攔截優化

番茄西紅柿 / 2029人閱讀

目錄介紹

01.網絡請求異常分類

02.開發中注意問題

03.原始的處理方式

04.如何減少代碼耦合性

05.異常統一處理步驟

06.完成版代碼展示

好消息

博客筆記大匯總【16年3月到至今】,包括Java基礎及深入知識點,Android技術博客,Python學習筆記等等,還包括平時開發中遇到的bug匯總,當然也在工作之余收集了大量的面試題,長期更新維護并且修正,持續完善……開源的文件是markdown格式的!同時也開源了生活博客,從12年起,積累共計N篇[近100萬字,陸續搬到網上],轉載請注明出處,謝謝!

鏈接地址:github.com/yangchong21…

如果覺得好,可以star一下,謝謝!當然也歡迎提出建議,萬事起于忽微,量變引起質變!

01.網絡請求異常分類

網絡請求異常大概有哪些?

第一種:訪問接口異常,比如404,500等異常,出現這類異常,Retrofit會自動拋出異常。

第二種:解析數據異常,數據體發生變化可能會導致這個問題。

第三種:其他類型異常,比如服務器響應超時異常,鏈接失敗異常,網絡未連接異常等等。

第四種:網絡請求成功,但是服務器定義了異常狀態,比如token失效,參數傳遞錯誤,或者統一給提示(這個地方比較拗口,比如購物app,你購買n件商品請求接口成功,code為200,但是服務器發現沒有這么多商品,這個時候就會給你一個提示,然后客戶端拿到這個進行吐司)

02.開發中注意問題

在獲取數據的流程中,訪問接口和解析數據時都有可能會出錯,我們可以通過攔截器在這兩層攔截錯誤。

1.在訪問接口時,我們不用設置攔截器,因為一旦出現錯誤,Retrofit會自動拋出異常。比如,常見請求異常404,500,503等等。為了方便后期排查問題,這個可以在debug環境下打印日志就可以。

2.在解析數據時,我們設置一個攔截器,判斷Result里面的code是否為成功,如果不成功,則要根據與服務器約定好的錯誤碼來拋出對應的異常。比如,token失效后跳轉登錄頁面,禁用同賬號登陸多臺設備,缺少參數,參數傳遞異常等等。

3.除此以外,為了我們要盡量避免在View層對錯誤進行判斷,處理,我們必須還要設置一個攔截器,攔截onError事件,然后使用ExceptionUtils,讓其根據錯誤類型來分別處理。

03.原始的處理方式

最簡單的處理方式,直接對返回的throwable進行類型判斷處理

//請求,對throwable進行判斷
ServiceHelper.getInstance()
      .getModelResult(param1, param2)
      .subscribeOn(Schedulers.io())
      .observeOn(AndroidSchedulers.mainThread())
      .subscribe(new Subscriber() {
             @Override
              public void onCompleted() {
              
              }

              @Override
              public void onError(Throwable e) {
                  if(e instanceof HttpException){
	                  //獲取對應statusCode和Message
                      HttpException exception = (HttpException)e;
                      String message = exception.response().message();
                      int code = exception.response().code();
                  }else if(e instanceof SSLHandshakeException){
					//接下來就是各種異常類型判斷...
                  }else if(e instanceof ...){

                  }...
			  }

              @Override
              public void onNext(Model model) {
                  if(model.getCode != CODE_SUCCESS){
                        int code = model.getCode();
                        switch (code){
                            case CODE_TOKEN_INVALID:
                                ex.setDisplayMessage("重新登陸");
                                break;
                            case CODE_NO_OTHER:
                                ex.setDisplayMessage("其他情況");
                                break;
                            case CODE_SHOW_TOAST:
                                ex.setDisplayMessage("吐司服務器返回的提示");
                                break;
                            case CODE_NO_MISSING_PARAMETER:
                                ex.setDisplayMessage("缺少參數,用log記錄服務器提示");
                                break;
                            default:
                                ex.setDisplayMessage(message);
                                break;
                        }
                  }else{
                      //正常處理邏輯
                  }
              }
      });

04.如何減少代碼耦合性

為了不改變以前的代碼結構,那么如何做才能夠徹底解耦呢?一般情況下使用Retrofit網絡請求框架,會有回調方法,如下所示:

package retrofit2;

public interface Callback {
    void onResponse(Call var1, Response var2);

    void onFailure(Call var1, Throwable var2);
}

不管以前代碼封裝與否,都希望一句代碼即可實現網絡請求攔截處理邏輯。那么這個時候,我是怎么處理的呢?

public class ResponseData {

    private int code;
    private String message;
    private T t;

    public int getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }

    public T getT() {
        return t;
    }
}

new CallbacklogEntity>>(){
    @Override
    public void onResponse(CalllogEntity>> call,
                           ResponselogEntity>> response) {
        int code = response.body().getCode();
        String message = response.body().getMessage();
        HomeBlogEntity t = response.body().getT();
        if (code!= CODE_SUCCESS){
            //網絡請求成功200,不過業務層執行服務端制定的異常邏輯
            ExceptionUtils.serviceException(code,message);
        } else {
            //網絡請求成功,業務邏輯正常處理
        }
    }

    @Override
    public void onFailure(Call call, Throwable throwable) {
        ExceptionUtils.handleException(throwable);
    }
};

05.異常統一處理步驟

第一步:定義請求接口網絡層失敗的狀態碼

/**
 * 對應HTTP的狀態碼
 */
private static final int BAD_REQUEST = 400;
private static final int UNAUTHORIZED = 401;
private static final int FORBIDDEN = 403;
private static final int NOT_FOUND = 404;
private static final int METHOD_NOT_ALLOWED = 405;
private static final int REQUEST_TIMEOUT = 408;
private static final int CONFLICT = 409;
private static final int PRECONDITION_FAILED = 412;
private static final int INTERNAL_SERVER_ERROR = 500;
private static final int BAD_GATEWAY = 502;
private static final int SERVICE_UNAVAILABLE = 503;
private static final int GATEWAY_TIMEOUT = 504;

第二步,接口請求成功,業務層失敗,服務端定義異常狀態碼

比如,登錄過期,提醒用戶重新登錄;

比如,添加商品,但是服務端發現庫存不足,這個時候接口請求成功,服務端定義業務層失敗,服務端給出提示語,客戶端進行吐司

比如,請求接口,參數異常或者類型錯誤,請求code為200成功狀態,不過給出提示,這個時候客戶端用log打印服務端給出的提示語,方便快遞查找問題

比如,其他情況,接口請求成功,但是服務端定義業務層需要吐司服務端返回的對應提示語

/**
 * 服務器定義的狀態嗎
 * 比如:登錄過期,提醒用戶重新登錄;
 *      添加商品,但是服務端發現庫存不足,這個時候接口請求成功,服務端定義業務層失敗,服務端給出提示語,客戶端進行吐司
 *      請求接口,參數異常或者類型錯誤,請求code為200成功狀態,不過給出提示,這個時候客戶端用log打印服務端給出的提示語,方便快遞查找問題
 *      其他情況,接口請求成功,但是服務端定義業務層需要吐司服務端返回的對應提示語
 */
/**
 * 完全成功
 */
private static final int CODE_SUCCESS = 0;
/**
 * Token 失效
 */
public static final int CODE_TOKEN_INVALID = 401;
/**
 * 缺少參數
 */
public static final int CODE_NO_MISSING_PARAMETER = 400400;
/**
 * 其他情況
 */
public static final int CODE_NO_OTHER = 403;
/**
 * 統一提示
 */
public static final int CODE_SHOW_TOAST = 400000;

第三步,自定義Http層的異常和服務器定義的異常類

public class HttpException extends Exception {

    private int code;
    private String displayMessage;

    public HttpException(Throwable throwable, int code) {
        super(throwable);
        this.code = code;
    }

    public void setDisplayMessage(String displayMessage) {
        this.displayMessage = displayMessage;
    }

    public String getDisplayMessage() {
        return displayMessage;
    }

    public int getCode() {
        return code;
    }
}

public class ServerException extends RuntimeException {

    public int code;
    public String message;

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    @Override
    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

第四步,統一處理異常邏輯如下所示

/**
 * 這個可以處理服務器請求成功,但是業務邏輯失敗,比如token失效需要重新登陸
 * @param code                  自定義的code碼
 */
public static void serviceException(int code , String content){
    if (code != CODE_SUCCESS){
        ServerException serverException = new ServerException();
        serverException.setCode(code);
        serverException.setMessage(content);
        handleException(serverException);
    }
}

/**
 * 這個是處理網絡異常,也可以處理業務中的異常
 * @param e                     e異常
 */
public static void handleException(Throwable e){
    HttpException ex;
    //HTTP錯誤   網絡請求異常 比如常見404 500之類的等
    if (e instanceof retrofit2.HttpException){
        retrofit2.HttpException httpException = (retrofit2.HttpException) e;
        ex = new HttpException(e, ErrorCode.HTTP_ERROR);
        switch(httpException.code()){
            case BAD_REQUEST:
            case UNAUTHORIZED:
            case FORBIDDEN:
            case NOT_FOUND:
            case METHOD_NOT_ALLOWED:
            case REQUEST_TIMEOUT:
            case CONFLICT:
            case PRECONDITION_FAILED:
            case GATEWAY_TIMEOUT:
            case INTERNAL_SERVER_ERROR:
            case BAD_GATEWAY:
            case SERVICE_UNAVAILABLE:
                //均視為網絡錯誤
            default:
                ex.setDisplayMessage("網絡錯誤"+httpException.code());
                break;
        }
    } else if (e instanceof ServerException){
        //服務器返回的錯誤
        ServerException resultException = (ServerException) e;
        int code = resultException.getCode();
        String message = resultException.getMessage();
        ex = new HttpException(resultException, ErrorCode.SERVER_ERROR);
        switch (code){
            case CODE_TOKEN_INVALID:
                ex.setDisplayMessage("token失效");
                //下面這里可以統一處理跳轉登錄頁面的操作邏輯
                break;
            case CODE_NO_OTHER:
                ex.setDisplayMessage("其他情況");
                break;
            case CODE_SHOW_TOAST:
                ex.setDisplayMessage("吐司");
                break;
            case CODE_NO_MISSING_PARAMETER:
                ex.setDisplayMessage("缺少參數");
                break;
            default:
                ex.setDisplayMessage(message);
                break;
        }
    } else if (e instanceof JsonParseException
            || e instanceof JSONException
            || e instanceof ParseException){
        ex = new HttpException(e, ErrorCode.PARSE_ERROR);
        //均視為解析錯誤
        ex.setDisplayMessage("解析錯誤");
    }else if(e instanceof ConnectException){
        ex = new HttpException(e, ErrorCode.NETWORK_ERROR);
        //均視為網絡錯誤
        ex.setDisplayMessage("連接失敗");
    } else if(e instanceof java.net.UnknownHostException){
        ex = new HttpException(e, ErrorCode.NETWORK_ERROR);
        //網絡未連接
        ex.setDisplayMessage("網絡未連接");
    } else if (e instanceof SocketTimeoutException) {
        ex = new HttpException(e, ErrorCode.NETWORK_ERROR);
        //網絡未連接
        ex.setDisplayMessage("服務器響應超時");
    }  else {
        ex = new HttpException(e, ErrorCode.UNKNOWN);
        //未知錯誤
        ex.setDisplayMessage("未知錯誤");
    }
    String displayMessage = ex.getDisplayMessage();
    //這里直接吐司日志異常內容,注意正式項目中一定要注意吐司合適的內容
    ToastUtils.showRoundRectToast(displayMessage);
}

第五步,如何調用

@Override
public void onError(Throwable e) {
    //直接調用即可
    ExceptionUtils.handleException(e);
}

06.完成版代碼展示

如下所示

public class ExceptionUtils {

    /*
     * 在使用Retrofit+RxJava時,我們訪問接口,獲取數據的流程一般是這樣的:訂閱->訪問接口->解析數據->展示。
     * 如上所說,異常和錯誤本質是一樣的,因此我們要盡量避免在View層對錯誤進行判斷,處理。
     *
     * 在獲取數據的流程中,訪問接口和解析數據時都有可能會出錯,我們可以通過攔截器在這兩層攔截錯誤。
     * 1.在訪問接口時,我們不用設置攔截器,因為一旦出現錯誤,Retrofit會自動拋出異常。
     * 2.在解析數據時,我們設置一個攔截器,判斷Result里面的code是否為成功,如果不成功,則要根據與服務器約定好的錯誤碼來拋出對應的異常。
     * 3.除此以外,為了我們要盡量避免在View層對錯誤進行判斷,處理,我們必須還要設置一個攔截器,攔截onError事件,然后使用ExceptionHandler,讓其根據錯誤類型來分別處理。
     */



    /**
     * 對應HTTP的狀態碼
     */
    private static final int BAD_REQUEST = 400;
    private static final int UNAUTHORIZED = 401;
    private static final int FORBIDDEN = 403;
    private static final int NOT_FOUND = 404;
    private static final int METHOD_NOT_ALLOWED = 405;
    private static final int REQUEST_TIMEOUT = 408;
    private static final int CONFLICT = 409;
    private static final int PRECONDITION_FAILED = 412;
    private static final int INTERNAL_SERVER_ERROR = 500;
    private static final int BAD_GATEWAY = 502;
    private static final int SERVICE_UNAVAILABLE = 503;
    private static final int GATEWAY_TIMEOUT = 504;

    /**
     * 服務器定義的狀態嗎
     * 比如:登錄過期,提醒用戶重新登錄;
     *      添加商品,但是服務端發現庫存不足,這個時候接口請求成功,服務端定義業務層失敗,服務端給出提示語,客戶端進行吐司
     *      請求接口,參數異常或者類型錯誤,請求code為200成功狀態,不過給出提示,這個時候客戶端用log打印服務端給出的提示語,方便快遞查找問題
     *      其他情況,接口請求成功,但是服務端定義業務層需要吐司服務端返回的對應提示語
     */
    /**
     * 完全成功
     */
    private static final int CODE_SUCCESS = 0;
    /**
     * Token 失效
     */
    public static final int CODE_TOKEN_INVALID = 401;
    /**
     * 缺少參數
     */
    public static final int CODE_NO_MISSING_PARAMETER = 400400;
    /**
     * 其他情況
     */
    public static final int CODE_NO_OTHER = 403;
    /**
     * 統一提示
     */
    public static final int CODE_SHOW_TOAST = 400000;



    /**
     * 這個可以處理服務器請求成功,但是業務邏輯失敗,比如token失效需要重新登陸
     * @param code                  自定義的code碼
     */
    public static void serviceException(int code , String content){
        if (code != CODE_SUCCESS){
            ServerException serverException = new ServerException();
            serverException.setCode(code);
            serverException.setMessage(content);
            handleException(serverException);
        }
    }

    /**
     * 這個是處理網絡異常,也可以處理業務中的異常
     * @param e                     e異常
     */
    public static void handleException(Throwable e){
        HttpException ex;
        //HTTP錯誤   網絡請求異常 比如常見404 500之類的等
        if (e instanceof retrofit2.HttpException){
            retrofit2.HttpException httpException = (retrofit2.HttpException) e;
            ex = new HttpException(e, ErrorCode.HTTP_ERROR);
            switch(httpException.code()){
                case BAD_REQUEST:
                case UNAUTHORIZED:
                case FORBIDDEN:
                case NOT_FOUND:
                case METHOD_NOT_ALLOWED:
                case REQUEST_TIMEOUT:
                case CONFLICT:
                case PRECONDITION_FAILED:
                case GATEWAY_TIMEOUT:
                case INTERNAL_SERVER_ERROR:
                case BAD_GATEWAY:
                case SERVICE_UNAVAILABLE:
                    //均視為網絡錯誤
                default:
                    ex.setDisplayMessage("網絡錯誤"+httpException.code());
                    break;
            }
        } else if (e instanceof ServerException){
            //服務器返回的錯誤
            ServerException resultException = (ServerException) e;
            int code = resultException.getCode();
            String message = resultException.getMessage();
            ex = new HttpException(resultException, ErrorCode.SERVER_ERROR);
            switch (code){
                case CODE_TOKEN_INVALID:
                    ex.setDisplayMessage("重新登陸");
                    break;
                case CODE_NO_OTHER:
                    ex.setDisplayMessage("其他情況");
                    break;
                case CODE_SHOW_TOAST:
                    ex.setDisplayMessage("吐司");
                    break;
                case CODE_NO_MISSING_PARAMETER:
                    ex.setDisplayMessage("缺少參數");
                    break;
                default:
                    ex.setDisplayMessage(message);
                    break;
            }
        } else if (e instanceof JsonParseException
                || e instanceof JSONException
                || e instanceof ParseException){
            ex = new HttpException(e, ErrorCode.PARSE_ERROR);
            //均視為解析錯誤
            ex.setDisplayMessage("解析錯誤");
        }else if(e instanceof ConnectException){
            ex = new HttpException(e, ErrorCode.NETWORK_ERROR);
            //均視為網絡錯誤
            ex.setDisplayMessage("連接失敗");
        } else if(e instanceof java.net.UnknownHostException){
            ex = new HttpException(e, ErrorCode.NETWORK_ERROR);
            //網絡未連接
            ex.setDisplayMessage("網絡未連接");
        } else if (e instanceof SocketTimeoutException) {
            ex = new HttpException(e, ErrorCode.NETWORK_ERROR);
            //網絡未連接
            ex.setDisplayMessage("服務器響應超時");
        }  else {
            ex = new HttpException(e, ErrorCode.UNKNOWN);
            //未知錯誤
            ex.setDisplayMessage("未知錯誤");
        }
        String displayMessage = ex.getDisplayMessage();
        //這里直接吐司日志異常內容,注意正式項目中一定要注意吐司合適的內容
        ToastUtils.showRoundRectToast(displayMessage);
    }
}

其他介紹

01.關于博客匯總鏈接

1.技術博客匯總

2.開源項目匯總

3.生活博客匯總

4.喜馬拉雅音頻匯總

5.其他匯總

02.關于我的博客

github:github.com/yangchong21…

知乎:www.zhihu.com/people/yczb…

簡書:www.jianshu.com/u/b7b2c6ed9…

csdn:my.csdn.net/m0_37700275

喜馬拉雅聽書:www.ximalaya.com/zhubo/71989…

開源中國:my.oschina.net/zbj1618/blo…

泡在網上的日子:www.jcodecraeer.com/member/cont…

郵箱:yangchong211@163.com

阿里云博客:yq.aliyun.com/users/artic… 239.headeruserinfo.3.dT4bcV

segmentfault頭條:segmentfault.com/u/xiangjian…

掘金:juejin.im/user/593943…

開源代碼案例:github.com/yangchong21…

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/7056.html

相關文章

  • 網絡請求異常攔截優化

    目錄介紹 01.網絡請求異常分類 02.開發中注意問題 03.原始的處理方式 04.如何減少代碼耦合性 05.異常統一處理步驟 06.完成版代碼展示 好消息 博客筆記大匯總【16年3月到至今】,包括Java基礎及深入知識點,Android技術博客,Python學習筆記等等,還包括平時開發中遇到的bug匯總,當然也在工作之余收集了大量的面試題,長期更新維護并且修正,持續完善……開源的文件是ma...

    lemon 評論0 收藏0
  • Android優化總結

    摘要:錯誤使用單利在開發中單例經常需要持有對象,如果持有的對象生命周期與單例生命周期更短時,或導致無法被釋放回收,則有可能造成內存泄漏。如果集合是類型的話,那內存泄漏情況就會更為嚴重。 目錄介紹 1.OOM和崩潰優化 1.1 OOM優化 1.2 ANR優化 1.3 Crash優化 2.內存泄漏優化 2.0 動畫資源未釋放 2.1 錯誤使用單利 2.2 錯誤使用靜態變量 2.3 ...

    sunsmell 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<