JAVA HttpClient重发、超时不生效

HttpClient真的是一个神奇的东西,版本之间差异过大,V4.3之前,V4.3以后V4.5以前,V4.5以后都几本是不兼容。所以JAVA在这一块的开发真的是十分头疼。

这位仁兄在深深的被折磨后很好的帮我们总结了HTTP不同版本超时

然而,本人在HttpClient 4.3.6版本下,试了无数次。。还是走不通。虽然已经把RequestConfig加到配置里面了,而且断点跟踪也看到配置已配好,也加在httpPost对象里面。但是,它就是不生效,我也很无奈。

所以,改用HttpUrlConnection进行发起POST请求。发现可以,代码如下。

  •  其中,data是一个普通的POJO,可以转成json然后再转成String,作为请求实体。
  •  一定要养好设置编码的习惯,不管是请求内容还是返回的数据流。
  • 请求结束后一定要把可以关的都关闭
  • 一部分代码是为了忽略SSL证书错误才写的。如果没有这个需求,去掉此段代码。
        
        HttpsURLConnection httpUrlCoNN = null;
        OutputStream outputStrem = null;
        OutputStreamWriter outWrite = null;
        InputStream inputStream = null;
        InputStreamReader inputReader = null;
        BufferedReader bufferReader = null;
        
        String tmpLineStr = null;
        StringBuffer resultBuffer = new StringBuffer();
        
        try{
        	trustAllHttpCertifications();
        	HostnameVerifier verify = new HostnameVerifier() {
				
				@Override
				public boolean verify(String arg0, SSLSession arg1) {
					// TODO Auto-generated method stub
					return true;
				}
			};
			HttpsURLConnection.setDefaultHostnameVerifier(verify);
        	
        	String dataParam = JSON.toJSONString(data);
        	URL url = new URL(Url);
        	URLConnection urlConn = url.openConnection();
        	httpUrlCoNN = (HttpsURLConnection) urlConn;
        	httpUrlCoNN.setDoInput(true);
        	httpUrlCoNN.setDoOutput(true);
        	
        	//超时
        	int timeoutMilSec = 60000;
        	httpUrlCoNN.setConnectTimeout(timeoutMilSec);
        	httpUrlCoNN.setReadTimeout(timeoutMilSec);
        	
        	httpUrlCoNN.setUseCaches(false);
        	httpUrlCoNN.setRequestMethod("POST");
        	httpUrlCoNN.setRequestProperty("Connection", "Keep-Alive");
        	httpUrlCoNN.setRequestProperty("Accept-Charset", "UTF-8");
        	httpUrlCoNN.setRequestProperty("Content-Type", "application/json;charsert=utf-8");
        	httpUrlCoNN.setRequestProperty("Content-Length", String.valueOf(dataParam.length()));
        	
        	
        	outputStrem = httpUrlCoNN.getOutputStream();
        	outWrite = new OutputStreamWriter(outputStrem);
        	outWrite.write(dataParam.toString());
        	outWrite.flush();
        	if(httpUrlCoNN.getResponseCode() >= 300){
        		//返回错
        		log.info("httpResultCode = {}",httpUrlCoNN.getResponseCode());
        		return null;
        	}
        	//接收响应流
        	inputStream = httpUrlCoNN.getInputStream();
        	inputReader = new InputStreamReader(inputStream,"UTF-8");
        	bufferReader = new BufferedReader(inputReader);
        	
        	while((tmpLineStr = bufferReader.readLine())!= null){
        		resultBuffer.append(tmpLineStr);
        	}
        }catch(Exception e){
        	log.info("return  = {}",e.getMessage());
        }finally{
        	if(null != outWrite){
        		outWrite.close();
        	}
        	if(null != outputStrem){
        		outputStrem.close();
        	}
        	if(null != bufferReader){
        		bufferReader.close();
        	}
        	if(null != inputReader){
        		inputReader.close();
        	}
        	if(null != inputStream){
        		inputStream.close();
        	}
        	if(null != httpUrlCoNN){
        		httpUrlCoNN.disconnect();
        	}
        }

这部分代码是为了忽略SSL证书错误才写的。如果没有这个需求,去掉此段代码。

    private void  trustAllHttpCertifications(){
		TrustManager[] trustAllCerts = new TrustManager[1];
		TrustManager tm = new miTM();
		trustAllCerts[0] = tm;
		SSLContext sc = null;
		try {
			sc = SSLContext.getInstance("SSL");
			sc.init(null, trustAllCerts, null);
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (KeyManagementException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
	}
	
	class miTM implements TrustManager,X509TrustManager{

		@Override
		public void checkClientTrusted(X509Certificate[] arg0, String arg1)
				throws CertificateException {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void checkServerTrusted(X509Certificate[] arg0, String arg1)
				throws CertificateException {
			// TODO Auto-generated method stub
			
		}

		@Override
		public X509Certificate[] getAcceptedIssuers() {
			// TODO Auto-generated method stub
			return null;
		}
		
		public boolean isServerTrusted(X509Certificate[] certs){
			return true;
		}
		
		public boolean isClientTrusted(X509Certificate[] certs){
			return true;
		}
		
	}


1)如果新建线程,然后在线程里发起http请求,一定要做超时控制。要不然,先不说会一直存在http连接,占用带宽,如果线程先于http请求断开,会导致报出SocketException。而且此时,这个报错是不可以通过IOException捕获(我也知道SocketException是继承了IOException,但是无奈人家就在这种情况下不会捕获)。你只能使用catch (Throwable e){}来做处理。但是,此时,就算捕获到,但是该线程在线程池里也不能重新运行了。

2)这是经验,可以运用到其他地方:因为HttpClient相对于HttpUrlConnection而言,只是做了一层封装。如果不同的版本都不能使配置生效的时候,可以直接使用封装之前的自己来构造。这样子可以避免版本的差异性

3)HTTPClient对于超时是会自动发起3次自动重连。如果你的http请求是在线程里发起的。那就需要注意一下这一部分的消耗了。可以手动在代码里把重发关闭。黄色部分。(老夫虽然用下面那代码控制了自动重发,但是无奈,没有把超时控制住,所以只能弃了这一版。)

        HttpPost httpPost = new HttpPost(Url);
		
        HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() {
			
			@Override
			public boolean retryRequest(IOException arg0, int arg1, HttpContext arg2) {
				// TODO Auto-generated method stub
				return false;
			}
		};
        int miSec =  60000;//超时时间
        RequestConfig requestConf = RequestConfig.custom().setConnectTimeout(miSec).setConnectionRequestTimeout(miSec)
        		.setSocketTimeout(miSec).build();
        
        
        
        
        CloseableHttpClient client = HttpClients.custom().setRetryHandler(myRetryHandler).build();
        StringEntity entity = new StringEntity(JSON.toJSONString(data), "utf-8");// 解决中文乱码问题
        entity.setContentEncoding("UTF-8");
        //FIXME
        entity.setContentType(MediaType.APPLICATION_JSON_VALUE);
        entity.setContentEncoding("UTF-8");
        httpPost.setEntity(entity);
        httpPost.setConfig(requestConf);
        httpPost.addHeader("Accept", MediaType.APPLICATION_JSON.toString());
        HttpResponse resp = null;
        try {
            resp = client.execute(httpPost);
            result = JSON.parseObject(resp.getEntity().getContent(),JSONObject.class);
        } catch (Throwable e) {
            //e.printStackTrace();
        	log.info(e.getMessage());
        	return null;
        }finally {
             httpPost.releaseConnection();
            if(null != client){
	        try {
		      client.close();
	        } catch (IOException e) {
		     // TODO Auto-generated catch block
		     e.printStackTrace();
	        }
	}



猜你喜欢

转载自blog.csdn.net/weixin_41048746/article/details/80364899