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.mzph.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;通过实际的演示让没使用过苹…