restTemplate请求重发的相关设置-通过配置

通过配置的方式

相关的pom文件需要引入:httpclient

<dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.13</version>
</dependency>

根据响应的HTTP状态码重试

在RestTemplate中有一个服务不可用重试配置,可以通过httpClientBuilder.setServiceUnavailableRetryStrategy来进行相关配置。通过查看源码可以发现,此处需要一个ServiceUnavailableRetryStrategy的实现,该接口已有一个默认的DefaultServiceUnavailableRetryStrategy配置。

默认的配置中,构造器代码如下:

public DefaultServiceUnavailableRetryStrategy(int maxRetries, int retryInterval) {Args.positive(maxRetries, "Max retries");Args.positive(retryInterval, "Retry interval");this.maxRetries = maxRetries;this.retryInterval = (long)retryInterval;
}public DefaultServiceUnavailableRetryStrategy() {this(1, 1000);
}

从默认的构造器源码中可以得到以下信息:

  • 可以设置两个参数,一个是重试次数,一个是重试时间间隔。
  • 默认的最大重试次数为1次,重试时间间隔为1s。

判断的相关代码如下:

public boolean retryRequest(HttpResponse response, int executionCount, HttpContext context) {return executionCount <= this.maxRetries && response.getStatusLine().getStatusCode() == 503;}
  • 可以看出就是一个简单的判断,判断执行次数是否小于最大重试次数且返回的状态码是否为503.
如何定制自己需要的配置
  • 次数和时间默认的配置已经给了构造方法。
  • 如果想根据不同的状态则可以通过自己写一个类实现ServiceUnavailableRetryStrategy
package com.doordiey.game.config;import org.apache.http.HttpResponse;
import org.apache.http.client.ServiceUnavailableRetryStrategy;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.Args;/*** 根据返回的HTTP状态码决定是否要重试*/
public class MyDefaultServiceUnavailableRetryStrategy implements ServiceUnavailableRetryStrategy {private final int maxRetries;private final long retryInterval;public MyDefaultServiceUnavailableRetryStrategy(int maxRetries, int retryInterval) {Args.positive(maxRetries, "Max retries");Args.positive(retryInterval, "Retry interval");this.maxRetries = maxRetries;this.retryInterval = (long)retryInterval;}public MyDefaultServiceUnavailableRetryStrategy() {this(1, 1000);}/*** 修改此处的判断* @param response* @param executionCount* @param context* @return*/public boolean retryRequest(HttpResponse response, int executionCount, HttpContext context) {return executionCount <= this.maxRetries && (response.getStatusLine().getStatusCode() == 503||response.getStatusLine().getStatusCode() == 502);}public long getRetryInterval() {return this.retryInterval;}
}

配置类

package com.doordiey.game.config;import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;import org.apache.http.client.HttpClient;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;@Configuration
public class RestTemplateConfig {private static Logger logger = LoggerFactory.getLogger(RestTemplateConfig.class);@Beanpublic RestTemplate restTemplate() {RestTemplate restTemplate = new RestTemplate();restTemplate.setRequestFactory(clientHttpRequestFactory());restTemplate.setErrorHandler(new DefaultResponseErrorHandler());return restTemplate;}@Beanpublic HttpComponentsClientHttpRequestFactory clientHttpRequestFactory() {try {HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {return true;}}).build();httpClientBuilder.setSSLContext(sslContext);HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext,hostnameVerifier);Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", sslConnectionSocketFactory).build();// 注册http和https请求// 开始设置连接池PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);httpClientBuilder.setServiceUnavailableRetryStrategy(new MyDefaultServiceUnavailableRetryStrategy());httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)); // 重试次数HttpClient httpClient = httpClientBuilder.build();HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); // httpClient连接配置return clientHttpRequestFactory;} catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {logger.error("初始化HTTP连接池出错", e);}return null;}}

测试的接口

package com.doordiey.game.controller;import com.doordiey.game.GameApplication;
import com.sun.corba.se.spi.ior.ObjectKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;import java.util.Map;@RestController
public class GameController {public static Logger logger = LoggerFactory.getLogger(GameApplication.class);@AutowiredRestTemplate restTemplate;@GetMapping("/play")@ResponseStatus(code=HttpStatus.SERVICE_UNAVAILABLE,reason="server error")public String play(){logger.info("play");return "ok";}@GetMapping("/test")public void test(){logger.info("test");RestTemplate restTemplate = new RestTemplate();String gg = restTemplate.getForObject("http://127.0.0.1:8086/play",String.class);logger.info(gg);}}

请求错误重试

在RestTemplate中请求错误重试可以通过httpClientBuilder.setRetryHandler 来进行相关配置。通过查看源码可以发现,此处需要set一个HttpRequestRetryHandler的实现,已经提供了一个默认的DefaultHttpRequestRetryHandler

默认的配置中,构造器代码如下:

protected DefaultHttpRequestRetryHandler(int retryCount, boolean requestSentRetryEnabled, Collection<Class<? extends IOException>> clazzes) {this.retryCount = retryCount;this.requestSentRetryEnabled = requestSentRetryEnabled;this.nonRetriableClasses = new HashSet();Iterator i$ = clazzes.iterator();while(i$.hasNext()) {Class<? extends IOException> clazz = (Class)i$.next();this.nonRetriableClasses.add(clazz);}}public DefaultHttpRequestRetryHandler(int retryCount, boolean requestSentRetryEnabled) {this(retryCount, requestSentRetryEnabled, Arrays.asList(InterruptedIOException.class, UnknownHostException.class, ConnectException.class, SSLException.class));}public DefaultHttpRequestRetryHandler() {this(3, false);}

从默认的构造器源码中可以得到以下几个信息:

  • 默认的重试次数为3次,且默认是不进行请求重发的。
  • 对请求报错中的InterruptedIOException.class, UnknownHostException.class, ConnectException.class, SSLException.class这四个错误类会特殊处理。

源码中主要进行是否重发的判断的是下面的代码:

public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {Args.notNull(exception, "Exception parameter");Args.notNull(context, "HTTP context");if (executionCount > this.retryCount) {return false;} else if (this.nonRetriableClasses.contains(exception.getClass())) {return false;} else {Iterator i$ = this.nonRetriableClasses.iterator();Class rejectException;do {if (!i$.hasNext()) {HttpClientContext clientContext = HttpClientContext.adapt(context);HttpRequest request = clientContext.getRequest();if (this.requestIsAborted(request)) {return false;}if (this.handleAsIdempotent(request)) {return true;}if (clientContext.isRequestSent() && !this.requestSentRetryEnabled) {return false;}return true;}rejectException = (Class)i$.next();} while(!rejectException.isInstance(exception));return false;}}

从判断部分的源码可以得到以下信息:

  • 先校验重试次数,再校验是否是那几个特殊的报错类,再进行其他校验。
综合以上得到的信息
  • 可以通过设置重试次数,再非特殊报错的情况下,请求进行多次重试。

restTemplate请求重发的相关设置-通过配置相关推荐

  1. Linux 大规模请求服务器连接数相关设置

    2019独角兽企业重金招聘Python工程师标准>>> 一般一个大规模Linux服务器请求数可能是几十万上百万的情况,需要足够的连接数来使用,所以务必进行相应的设置. 默认的Linu ...

  2. java协变 生产者理解_Linux 大规模请求服务器连接数相关设置

    一般一个大规模Linux服务器请求数可能是几十万上百万的情况,需要足够的连接数来使用,所以务必进行相应的设置. 默认的Linux服务器文件描述符等打开最大是1024,用ulimit -a 查看: [v ...

  3. aop springboot 传入参数_java相关:springboot配置aop切面日志打印过程解析

    java相关:springboot配置aop切面日志打印过程解析 发布于 2020-3-31| 复制链接 摘记: 这篇文章主要介绍了springboot配置aop切面日志打印过程解析,文中通过示例代码 ...

  4. 04.local_gateway和network相关设置

    文章目录 1. cluster restart的一些相关设置 1. gateway.expected_nodes: 2. gateway.expected_master_nodes: 3. gatew ...

  5. 系统配置microsoft服务器,Windows 评估服务设置和配置

    Windows 评估服务设置和配置 05/05/2017 本文内容 本主题中的部分介绍如何设置和配置 Windows 评估服务. 初始化 Windows 评估服务 若要初始化 Windows 评估服务 ...

  6. RestTemplate请求Could not extract response: no suitable HttpMessageConverter found for response type..

    使用 Spring Boot 写项目,需要用到微信接口获取用户信息. 在 Jessey 和 Spring RestTemplate 两个 Rest 客户端中,想到尽量不引入更多的东西,然后就选择了 S ...

  7. Linux下PHP开发之旅-2.开发环境相关设置探索

    一.默认目录在哪儿? 开始时面对该xampp集成开发环境的相关配置有点不知所错,于是便先想着找httpd.conf,通过该文件,对该集成环境的配置文件关系有了大致了解,具体操作如下; cd /opt/ ...

  8. PostMan和RestTemplate请求/oauth/token获取token报401错误

     报错: "timestamp": "2022-04-28T03:00:27.785+0000", "status": 401, " ...

  9. 运行一段时间后,RestTemplate请求报400错误

    问题描述 本地调用远端接口无误,部署到服务器上调用刚开始也无误,随着时间的推移,调用次数的增加,再次调用时报 400 Bad Request 错误. 问题代码 private String sendR ...

最新文章

  1. InfluxDB 分布式时间序列数据库环境搭建——据qcon大会2016qiniu说集群很坑且闭源了...
  2. 跨年过程中因日期格式化引发的生产故障:格式化方式YYYYMMdd和yyyyMMdd的区别
  3. 微机原理换行代码_东华大学微机原理课程设计--代码转换
  4. java学习(42):巩固练习
  5. java 自定义结构_java自定义构造二叉树及其遍历
  6. android自动运行服务,Android开机自启动服务的实现方法
  7. 2022美赛备赛资料大全
  8. 《移动通信原理与系统》——第二章《移动通信电波传播与传播预测模型》——笔记
  9. # 数学基础task 01 函数极限与连续性
  10. 打印没反应/打印耗时长/not accessible
  11. 嵌入式linux IIO驱动
  12. python获取图片像素点颜色_Python获取图片位置像素色值及判断色值是否存在
  13. 联想笔记本声音太小怎么办_笔记本声音太小,小编告诉你笔记本电脑声音太小解决方法...
  14. 记一个chrome自带input:-internal-autofill-selected背景色样式问题
  15. matlab中map工具箱(Mapping toolbox)使用
  16. 折叠共源共栅放大器(一)项目报告/实验/论文/比赛
  17. 新华社客户端文章:区块链金融:新蓝海还是新挑战
  18. 微信小程序getWXACodeUnlimit接口调用和返回二进制流转换成图片保存到本地
  19. java-net-php-python-jsp学生会人事管理信息系统计算机毕业设计程序
  20. html新闻发布系统源码,新闻发布系统源代码

热门文章

  1. 个人所得税累计减除费用怎么计算
  2. 【论文阅读】Revisiting Long-tailed Image Classification: Survey and Benchmarks with New Evaluation Metrics
  3. 大棚温湿度监控管理系统
  4. 【裴蜀定理】牛牛的方程式
  5. R语言ggplot2图例标签、标题、顺序修改和删除
  6. 在Linux下编译带调试功能的Bochs
  7. window10的快捷键和触控板小技巧
  8. 小米10pro使用说明书_小米10pro_5G手机参数和设置
  9. prettyPhoto
  10. 计算机技术会议,第五届信息科学、计算机技术与交通运输国际学术会议(ISCTT 2020)...