HttpClient

配置

connectionRequestTimeout :从连接池中获取可用连接的时间
connectTimeout :连接超时时间,客户端请求服务器与服务器建立连接(三次握手)成功的最大接受时间
socketTimeout :请求获取数据的超时时间,访问一个接口指定时间内无法返回数据,直接放弃此次调用
MaxtTotal是整个池子的大小
DefaultMaxPerRoute是根据连接到的主机对MaxTotal的一个细分,默认是2
//http client的重试次数,默认是3次
setHttpRequestRetryHandler
#提交请求前测试连接是否可用
http.staleConnectionCheckEnabled=true
#连接池的最大连接数,0代表不限;如果取0,需要考虑连接泄露导致系统崩溃的后果
http-client.pool.maxTotal=1000
#每个路由的最大连接数,如果只调用一个地址,可以将其设置为最大连接数
http-client.pool.defaultMaxPerRoute=200
#空闲多长时间(毫秒)来校验连接的有效性
http-client.pool.validateAfterInactivity=2000
#指客户端和服务器建立连接的超时时间 (ms) 
#最大约21秒,因为内部tcp在进行三次握手建立连接时,默认tcp超时时间是20秒,即便设置100s也是在21s后报错.
http-client.pool.connectTimeout=3000
#指客户端从服务器读取数据包的间隔超时时间,不是总读取时间,也就是socket timeout,ms
http-client.pool.socketTimeout=5000
#从连接池获取连接的timeout,不宜过大,ms
http-client.pool.connectionRequestTimout=200
#重试次数
http-client.pool.retryTimes=5
http-client.pool.charset=UTF-8
#若是少数固定客户端,长时间高频次的访问服务器,启用keep-alive非常合适!
#长连接保持时间 单位s,不宜过长
http-client.pool.keepAliveTime=10
#针对项目的特定业务(拆分Excel)保持长连接时间(单位:s)
http-client.pool.splitAliURLKeepAliveTime=30
#长连接内最多请求次数
#在keepAliveTime时间内每来一个新的请求,keepAliveTimeMaxConn会自动减1,直到为0,强制断掉连接
#http-client.pool.keepAliveTimeMaxConn=1000
#客户端在发送Request Message之前,先判断服务器是否愿意接受客户端发送的消息主体
http-client.pool.expectContinueEnabled=false
#定义连接管理器将由多个客户端实例共享。
#如果连接管理器是共享的,则其生命周期应由调用者管理,如果客户端关闭则不会关闭。
http-client.pool.connectionManagerShared=true

MyHttpClientConfig

@Data
@ConfigurationProperties(prefix="http-client.pool")
@Component
public class MyHttpClientProperties {
	private int maxTotal;
	private int defaultMaxPerRoute;
	private int connectTimeout;
	private int socketTimeout;
	private int connectionRequestTimout;
	private int retryTimes;
	private String charset;
	private int keepAliveTime;
	private int validateAfterInactivity;
	private int splitAliURLKeepAliveTime;
	private Boolean expectContinueEnabled;
	private Boolean connectionManagerShared;
}
@Configuration
public class MyHttpClientConfig {
	
	private static final String MY_COOKIE_EASY = "easy";
	
	@Autowired
	private MyHttpClientProperties hp;

	@Bean
	public PoolingHttpClientConnectionManager poolingHttpClientConnectionManager() {
		PoolingHttpClientConnectionManager phccm = new PoolingHttpClientConnectionManager();
		//连接池的最大连接数
		phccm.setMaxTotal(hp.getMaxTotal());
		phccm.setDefaultMaxPerRoute(hp.getDefaultMaxPerRoute());
		phccm.setValidateAfterInactivity(hp.getValidateAfterInactivity());
		return phccm;
	}
	/**
	 * 自定义cookie策略
	 * @author WenYueGuang
	 * @date 2020年12月7日
	 */
	public CookieSpecProvider easyCookieSpecProvider() {
		return new CookieSpecProvider() {
			@Override
			public CookieSpec create(HttpContext context) {
				return new DefaultCookieSpec() {
					@Override
					public void validate(Cookie cookie, CookieOrigin origin) throws MalformedCookieException {
						//DO NOTHING
					}
				};
			}
		};
	}
	/**
	 * 自定义cookie策略
	 * Standard strict(严格):状态管理策略行为完全符合RFC6265第四章的行为定义
	 * Standard(标准):状态管理策略较为符合RFC6265第四章定义的行为,以期望在不是完全遵守该行为之间的服务器之间进行交互
	 * Default:默认cookie策略是一种综合性的策略,其基于HTTP response返回的cookie属性如version信息,过期信息,与RFC2965,RFC2109或者Netscape草案兼容,该策略将会在下一个HttpClient小版本(基于RFC6265)中废弃
	 * Ignore cookies:所有的cookie都被忽略
	 * @author WenYueGuang
	 * @date 2020年12月7日
	 */
	public Registry<CookieSpecProvider> myCookieSpecProvider() {
		PublicSuffixMatcher publicSuffixMatcher = PublicSuffixMatcherLoader.getDefault();
		Registry<CookieSpecProvider> cs = RegistryBuilder.<CookieSpecProvider>create()
				.register(CookieSpecs.DEFAULT, new DefaultCookieSpecProvider(publicSuffixMatcher))
				.register(CookieSpecs.STANDARD,new RFC6265CookieSpecProvider(publicSuffixMatcher))
				.register(MY_COOKIE_EASY, easyCookieSpecProvider())
				.build();
		return cs;
	}
	@Bean
	public RequestConfig requestConfig() {
		return RequestConfig.custom()
				.setConnectionRequestTimeout(hp.getConnectionRequestTimout())//从链接池获取连接的超时时间
				.setConnectTimeout(hp.getConnectTimeout())//与服务器连接超时时间
				.setSocketTimeout(hp.getSocketTimeout())//从服务器获取数据的超时时间
				//客户端在发送Request Message之前,先判断服务器是否愿意接受客户端发送的消息主体
				.setExpectContinueEnabled(hp.getExpectContinueEnabled())
				//实际使用client的过程中,会遇到一种情况,如cookie的Key为空的,
				//此时默认的cookie的策略处理是:当程序中无需传递cookie值时会出现“Cookie rejected”的警告信息。
				//.setCookieSpec(CookieSpecs.DEFAULT)
				.setCookieSpec(MY_COOKIE_EASY)
				//.setCookieSpec(CookieSpecs.IGNORE_COOKIES)
				.build();
	}
	public ConnectionKeepAliveStrategy myStrategy() {
		return new ConnectionKeepAliveStrategy() {			
			@Override
			public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
				//有少数固定客户端,长时间极高频次的访问服务器,启用keep-alive非常合适
				HeaderElementIterator it = new BasicHeaderElementIterator(response.headerIterator(HTTP.CONN_KEEP_ALIVE));
				while(it.hasNext()) {
					HeaderElement he = it.nextElement();
					String param = he.getName();
					String value = he.getValue();
					if(value!=null && param.equalsIgnoreCase(MyConstant.TIMEOUT)) {
						try {
							return Long.parseLong(value)*MyConstant.THOUSAND;
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}
				HttpHost target = (HttpHost) context.getAttribute(HttpClientContext.HTTP_TARGET_HOST);
				if(MyConstant.ALI_URL_HOST.equalsIgnoreCase(target.getHostName())) {
					return hp.getSplitAliURLKeepAliveTime()*MyConstant.THOUSAND;
				}
				return hp.getKeepAliveTime()*MyConstant.THOUSAND;
			}
		};
	}
	public HttpRequestRetryHandler myRetry() {
		return new HttpRequestRetryHandler() {			
			@Override
			public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
				if (executionCount >= hp.getRetryTimes()) {// 如果已经重试了n次,就放弃
                    return false;
                }
                if (exception instanceof NoHttpResponseException) {// 如果服务器丢掉了连接,那么就重试
                    return true;
                }
                if (exception instanceof SSLHandshakeException) {// 不要重试SSL握手异常
                    return false;
                }
                if (exception instanceof InterruptedIOException) {// 超时
                    return false;
                }
                if (exception instanceof UnknownHostException) {// 目标服务器不可达
                    return false;
                }
                if (exception instanceof ConnectTimeoutException) {// 连接被拒绝
                    return false;
                }
                if (exception instanceof SSLException) {// SSL握手异常
                    return false;
                }

                HttpClientContext clientContext = HttpClientContext
                        .adapt(context);
                HttpRequest request = clientContext.getRequest();
                // 如果请求是幂等的,就再次尝试
                if (!(request instanceof HttpEntityEnclosingRequest)) {
                    return true;
                }
                return false;
			}
		};
		
	}
	@Bean
	public HttpClientBuilder httpClientBuilder(PoolingHttpClientConnectionManager phccm) {
		HttpClientBuilder hb = HttpClientBuilder.create();
		hb.setConnectionManager(phccm);
		hb.setDefaultCookieSpecRegistry(myCookieSpecProvider());
		hb.setDefaultRequestConfig(requestConfig());
		hb.setConnectionManagerShared(hp.getConnectionManagerShared());
		hb.setKeepAliveStrategy(myStrategy());
		hb.setRetryHandler(myRetry());
		//禁止重试
//		hb.disableAutomaticRetries();
		return hb;
	}
	@Bean
	public CloseableHttpClient getCloseableHttpClient(HttpClientBuilder hb) {
		return hb.build();
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值