Java生鮮電商平臺-SpringCloud微服務架構中網絡請求性能優化與源碼解析

Java生鮮電商平臺-SpringCloud微服務架構中網絡請求性能優化與源碼解析

?

說明:Java生鮮電商平臺中,由于服務進行了拆分,很多的業務服務導致了請求的網絡延遲與性能消耗,對應的這些問題,我們應該如何進行網絡請求的優化與處理呢?

到底有沒有一些好的建議與方案呢?

?

下面這個文章將揭曉上面的問題,讓你對SpringCloud微服務網絡請求性能有一個全新的認識.

?

目錄簡介

  • 01.網絡請求異常分類
  • 02.開發中注意問題
  • 03.原始的處理方式
  • 04.如何減少代碼耦合性
  • 05.異常統一處理步驟
  • 06.完成版代碼展示

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<Model>() {@Overridepublic 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<T> { void onResponse(Call<T> var1, Response<T> var2); void onFailure(Call<T> var1, Throwable var2); } 
  • 不管以前代碼封裝與否,都希望一句代碼即可實現網絡請求攔截處理邏輯。那么這個時候,我是怎么處理的呢?
public class ResponseData<T> { 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 Callback<ResponseData<HomeBlogEntity>>(){ @Override public void onResponse(Call<ResponseData<HomeBlogEntity>> call, Response<ResponseData<HomeBlogEntity>> 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); } } 

感謝你能讀到最后,希望能對你有所幫助。

?如果需要源代碼或者架構文檔的,請加QQ群:793305035

轉載于:https://www.cnblogs.com/jurendage/p/11357234.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/247141.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/247141.shtml
英文地址,請注明出處:http://en.pswp.cn/news/247141.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

XCode7 創建framework

1.新建一個靜態庫工程. file→ new→ project, 彈出框中選擇iOS→ framework & library中的cocoa touch static library.點擊Next,輸入product name: TestFramework, 點擊Next→ 點擊Create. 2.刪除向導所生成工程中的Target. 點擊工程名→ 點擊TARGETS → 右鍵Delete. …

基礎js逆向練習-登錄密碼破解(js逆向)

練習平臺&#xff1a;逆向賬號密碼 https://login1.scrape.center/ 直接打開平臺&#xff0c;輸入密碼賬號&#xff0c;抓包找到加密的參數攜帶的位置&#xff0c;這邊我們找到的是一個叫token的加密參數&#xff0c;這個參數的攜帶是一個密文 我們首先考慮一下搜索這個加密的…

python之socket

socket套接字 什么叫socket socket是處于應用層與傳輸層之間的抽象層,他是一組操作起來非常簡單的接口(接受數據)此接口接受數據之后,交由操作系統.socket在python中就是一個模塊. socket兩個分類 基于文件類型的套接字家族 套接字家族的名字&#xff1a;AF_UNIX unix一切皆文件…

iOS----JSON解析

在iOS開發中與服務器進行數據交互操作&#xff0c;操作過程中使用最為常見的格式為JSON與XML,其中JSON較為清量,因此本篇blog就講解一下如何在iOS中進行JSON解析。 1.建立HTTP請求 &#xff08;1&#xff09;創建URL NSString *URLStr [NSString stringWithFormat:”http:/…

VS中每次改代碼后運行程序不更新,只有重新編譯才生效。

解決方法&#xff1a;將項目移除解決方案&#xff0c;再重新添加進來&#xff0c;即添加->現有項目->選擇.vcxproj文件&#xff0c;即可解決。 轉載于:https://www.cnblogs.com/Gregg/p/11358711.html

socket補充:通信循環、鏈接循環、遠程操作及黏包現象

socket補充&#xff1a;通信循環、鏈接循環、遠程操作及黏包現象 socket通信循環 server端&#xff1a; import socketphone socket.socket(socket.AF_INET,socket.SOCK_STREAM)phone.bind((127.0.0.1,8080))phone.listen(5)conn, client_addr phone.accept() print(conn, cl…

PCA的原理及MATLAB實現

相關文章 PCA的原理及MATLAB實現 UFLDL教程&#xff1a;Exercise:PCA in 2D & PCA and Whitening python-A comparison of various Robust PCA implementations &#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&a…

Java生鮮電商平臺-SpringCloud微服務架構中核心要點和實現原理

Java生鮮電商平臺-SpringCloud微服務架構中核心要點和實現原理 說明&#xff1a;Java生鮮電商平臺中&#xff0c;我們將進一步理解微服務架構的核心要點和實現原理&#xff0c;為讀者的實踐提供微服務的設計模式&#xff0c;以期讓微服務在讀者正在工作的項目中起到積極的作用。…

iOS中下載小文件

在iOS中通過網絡下載小文件比如小型圖片等資源&#xff0c;一般在子線程中將數據完全下載完畢&#xff0c;然后在調用block將下載的數據整個部分返回&#xff0c;或者采用同步返回下載數據。 一般采用以下兩種方式&#xff1a; &#xff08;1&#xff09;使用GCD將下載操作放…

iOS下載大文件原理解析一

iOS中下載大型文件&#xff0c;需要考慮到占用內存的大小與下載速度&#xff08;使用多線程&#xff09;&#xff0c;因此本文首先介紹一個原理性下載文件的DEMO。 在下載大型文件中&#xff0c;需要知道下載的進度因此需要使用代理模式&#xff0c;不斷的回調下載進度。 - (…

recv原理、高階版黏包解決方案、基于UDP的socket通信

recv原理、高階版黏包解決方案、基于UDP的socket通信 recv原理 源碼解釋&#xff1a; Receive up to buffersize bytes from the socket. 接收來自socket緩沖區的字節數據&#xff0c; For the optional flags argument, see the Unix manual. 對于這些設置的參數&#xff0c;可…

iOS中下載大型文件的原理解析二

在iOS中下載大型文件&#xff0c;需要使用NSURLConnection 的代理方法&#xff1a; (void)touchesBegan:(NSSet)touches withEvent:(UIEvent *)event { NSURL *url [NSURL URLWithString:”http://d.3987.com/fengj_141112/007.jpg“]; NSURLRequest *request [NSURLReque…

ASP.NET Core Web 應用程序開發期間部署到IIS自定義主機域名并附加到進程調試

想必大家之前在進行ASP.NET Web 應用程序開發期間都有用到過將我們的網站部署到IIS自定義主機域名并附加到進程進行調試。 那我們的ASP.NET Core Web 應用程序又是如何部署到我們的IIS上面進行調試的呢&#xff0c;接下來我們來簡單介紹下&#xff1a; 一、安裝IIS所需的Host擴…

iOS下載大型文件原理解析三

在下載大型文件過程中是可以取消下載的 - (IBAction)download:(UIButton *)sender { // 狀態取反 sender.selected !sender.isSelected; // 斷點續傳 // 斷點下載if (sender.selected) { // 繼續&#xff08;開始&#xff09;下載// 1.URLNSURL *url [NSURL URLWithStrin…

HTML文件上傳與下載

文件下載 傳統的文件下載有兩種方法&#xff1a; 使用<a/>標簽&#xff0c;href屬性直接連接到服務器的文件路徑window.location.href"url"這兩種方法效果一樣。但有個很大的問題&#xff0c;如果下載出現異常&#xff08;連接路徑失效、文件不存在、網絡問題等…

NSURLSession的應用

iOS7以后發布了NSURLSession用來替換NSURLConnection&#xff0c;NSURLSession使用方式有以下兩種&#xff1a; 1.block方式 &#xff08;1&#xff09;創建的步驟 獲取單例會話對象 創建URL對象 隱含創建request 創建NSURLSessionDataTask // 1.獲取會話對象 NSURLSess…

ASP.NET Core Web 應用程序系列(一)- 使用ASP.NET Core內置的IoC容器DI進行批量依賴注入(MVC當中應用)...

在正式進入主題之前我們來看下幾個概念&#xff1a; 一、依賴倒置 依賴倒置是編程五大原則之一&#xff0c;即&#xff1a; 1、上層模塊不應該依賴于下層模塊&#xff0c;它們共同依賴于一個抽象。 2、抽象不能依賴于具體&#xff0c;具體依賴于抽象。 其中上層就是指使用者&am…

iOS中XML解析

iOS中XML解析分為兩種實現方式&#xff1a;SAX與DOM SAX方式&#xff1a;主要是事件驅動的解析方式&#xff0c;是逐行讀取XML數據&#xff0c;不斷回調代理&#xff0c;告訴代理當前解析的元素開始或者結束。 DOM解析方式&#xff1a;是講整個XML數據全部讀入內存&#xff0…

蘋果電腦基本設置+Linux 命令+Android 實戰集錦

本文微信公眾號「AndroidTraveler」首發。 背景 大多數應屆畢業生在大學期間使用的比較多的是 windows 電腦&#xff0c;因此初入職場如果拿到一臺蘋果電腦&#xff0c;可能一時間不能夠很快的上手。基于此&#xff0c;這邊出了系列視頻&#xff0c;通過實際的演示讓沒使用過蘋…