在项目上负责对接一些三方接口,鉴于之前的经验,选择使用RestTemplate来实现各种http请求,以及文件的读取。
首先写了RestTemplate的配置类来配置基础信息,代码如下:
@Configuration @ConditionalOnClass(value = {RestTemplate.class, HttpClient.class}) public class RestTemplateConfig { @Value("${remote.maxTotalConnect:1000}") private int maxTotalConnect; //连接池的最大连接数1000 @Value("${remote.maxConnectPerRoute:100}") private int maxConnectPerRoute; //单个主机的最大连接数200 @Value("${remote.connectTimeout:2000}") private int connectTimeout; //连接超时默认2s @Value("${remote.readTimeout:30000}") private int readTimeout; //读取超时默认30s @Value("${remote.readTimeout:10000}") private int connectionRequestTimeout; // 从连接池获取连接的超时时间默认10s //创建HTTP客户端工厂 private ClientHttpRequestFactory createFactory() { if (this.maxTotalConnect <= 0) { SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); factory.setConnectTimeout(this.connectTimeout); factory.setReadTimeout(this.readTimeout); return factory; } HttpClient httpClient = HttpClientBuilder.create().setMaxConnTotal(this.maxTotalConnect) .setMaxConnPerRoute(this.maxConnectPerRoute).setConnectionTimeToLive(30, TimeUnit.MINUTES).build(); HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory( httpClient); factory.setConnectTimeout(this.connectTimeout); factory.setReadTimeout(this.readTimeout); factory.setConnectionRequestTimeout(connectionRequestTimeout); return factory; } //初始化RestTemplate,并加入spring的Bean工厂,由spring统一管理 @Bean @ConditionalOnMissingBean(RestTemplate.class) public RestTemplate getRestTemplate() { RestTemplate restTemplate = new RestTemplate(this.createFactory()); //换上fastjson List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters(); Iterator<HttpMessageConverter<?>> iterator = messageConverters.iterator(); while (iterator.hasNext()) { HttpMessageConverter<?> converter = iterator.next(); //原有的String是ISO-8859-1编码 去掉 if (converter instanceof StringHttpMessageConverter) { iterator.remove(); } //由于系统中默认有jackson 在转换json时自动会启用 但是我们不想使用它 可以直接移除 if (converter instanceof GsonHttpMessageConverter || converter instanceof MappingJackson2HttpMessageConverter) { iterator.remove(); } } messageConverters.add(new StringHttpMessageConverter(Charset.forName("utf-8"))); FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter(); FastJsonConfig fastJsonConfig = new FastJsonConfig(); /** 设置支持的MediaType**/ List<MediaType> mediaTypes = new ArrayList<>(); mediaTypes.add(MediaType.APPLICATION_JSON); mediaTypes.add(MediaType.APPLICATION_ATOM_XML); mediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED); mediaTypes.add(MediaType.APPLICATION_OCTET_STREAM); mediaTypes.add(MediaType.APPLICATION_PDF); mediaTypes.add(MediaType.APPLICATION_RSS_XML); mediaTypes.add(MediaType.APPLICATION_XHTML_XML); mediaTypes.add(MediaType.APPLICATION_XML); mediaTypes.add(MediaType.IMAGE_GIF); mediaTypes.add(MediaType.IMAGE_JPEG); mediaTypes.add(MediaType.IMAGE_PNG); mediaTypes.add(MediaType.TEXT_EVENT_STREAM); mediaTypes.add(MediaType.TEXT_HTML); mediaTypes.add(MediaType.TEXT_MARKDOWN); mediaTypes.add(MediaType.TEXT_PLAIN); mediaTypes.add(MediaType.TEXT_XML); converter.setSupportedMediaTypes(mediaTypes); // 设置默认的字符集 converter.setDefaultCharset(Charset.forName("UTF-8")); // 设置默认的时间格式 JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; fastJsonConfig.setSerializerFeatures(SerializerFeature.WriteDateUseDateFormat); // 设置序列化方式 fastJsonConfig.setSerializerFeatures( //List字段如果为null,输出为[],而非null SerializerFeature.WriteNullListAsEmpty, //是否输出值为null的字段 SerializerFeature.WriteMapNullValue, //字符类型字段如果为null,输出为”“,而非null SerializerFeature.WriteNullStringAsEmpty, //消除对同一对象循环引用的问题 SerializerFeature.DisableCircularReferenceDetect); converter.setFastJsonConfig(fastJsonConfig); messageConverters.add(converter); return restTemplate; } }
然后在项目中用@Resource RestTemplate 使用就可以了;代码完成后打包启用一切正常。在测试环境运行一周后突然开始报错,测试反馈系统一直timed out,整个业务流程被阻断了
查看日志,确如测试同事所说,当天调用该方法的请求都出现了这个问题。这就尴尬了,之前也这么写的,为啥现在报错了,而且前一天还是正常的。一直没想通,改用httpClient方式,发现还是timed out。再看代码,是系统要连续读取两张照片,第一张读取时是没问题的,在读取第二张时,系统明显感觉发送完请求就假死了,一直到连接超时。
鉴于图片用两种读取方式都能读到第一张,所以想着用每种方式读取一张,看能不能完成本次需求,代码修改后,再次测试,系统正常跑完流程,未再报错。但是为什么用RestTemplate连续读取两次报错,一直不理解。直到查资料RestTemplate还有个connectionRequestTimeout时间设置。源码如下:
用翻译软件翻译结果如下:
设置请求连接时使用的超时(以毫秒为单位) 使用底层的{@link RequestConfig}从连接管理器获取。 超时值0指定无限超时。 其他属性可以通过指定 {@link RequestConfig}在自定义{@link HttpClient}上的实例。 请求连接的超时值,以毫秒为单位。
原来是RestTemplate,连接池关闭获取不到连接就报readtimeout异常,随后在RestTemplateConfiguration设置上connectionRequestTimeout时间10s,再次测试OK。与通过两种不同方式读取结果一致,都能完成业务正常流水。至此问题解决!
标签:读取,Read,RestTemplate,MediaType,add,mediaTypes,timed,converter From: https://www.cnblogs.com/yandugu/p/17869369.html