码迷,mamicode.com
首页 > 编程语言 > 详细

JAVA: httpclient 详解;

时间:2014-07-06 09:19:00      阅读:746      评论:0      收藏:0      [点我收藏+]

标签:java   httpclient   http协议   

相对于httpurlconnection ,httpclient更加丰富,也更加强大,其中apache有两个项目都是httpclient,一个是commonts包下的,这个是通用的,更专业的是org.apache.http.包下的,所以我一般用后者;


httpclient可以处理长连接,保存会话,重连接,以及请求过滤器,连接重用等等...


下面是测试代码(全部总结来自官方文档,以及翻译)


须要下载核心包:httpclient-4.3.4.jar ,也可在官网下载:http://hc.apache.org/downloads.cgi



package httpClientTest;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import javax.net.ssl.SSLException;

import org.apache.http.Consts;
import org.apache.http.HeaderElement;
import org.apache.http.HeaderElementIterator;
import org.apache.http.HttpClientConnection;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.client.utils.URIUtils;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.conn.ConnectionRequest;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.LaxRedirectStrategy;
import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
import org.apache.http.message.BasicHeaderElementIterator;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;

public class Main {

	
	public static void main(String[] args) {
		
		try {
			test9();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	
	
	
	
	/**
	 * 测试1: 构建复杂uri,这种方式会很方便的设置多个参数;
	 * 
	 * HttpClients类是client的具体一个实现类;
	 * 
	 * URIBuilder包含:协议,主机名,端口(可选),资源路径,和多个参数(可选)
	 * 
	 */
	private static void test1() {
		
		CloseableHttpClient client = HttpClients.createDefault();
		
		URI uri = null;
		try {
			uri = new URIBuilder()
			.setScheme("http")
			.setHost("webservice.webxml.com.cn")
			.setPath("/WebServices/MobileCodeWS.asmx/getDatabaseInfo")
			.setParameter("", "")//这里可以设置多个参数
			.setParameter("", "")
			.setParameter("", "")
			.setParameter("", "")
			.build();
		} catch (URISyntaxException e1) {
			e1.printStackTrace();
		}
		
		//http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx/getDatabaseInfo
		HttpGet get = new HttpGet(uri);
		try {
			CloseableHttpResponse response = client.execute(get);
			
			if(response.getStatusLine().getStatusCode()==200){
				
				
				System.out.println(EntityUtils.toString(response.getEntity()));
				
				//以下这种方式读取流也可以,只不过用EntityUtils会更方便
				/*InputStream is = response.getEntity().getContent();
				ByteArrayOutputStream os = new ByteArrayOutputStream();
				byte[] buffer = new byte[1024];
				int len=-1;
				while((len = is.read(buffer))!=-1){
					os.write(buffer,0,len);
				}
				os.close();
				is.close();
				System.out.println(os.size()+new String(os.toByteArray(),"utf-8"));*/
			}
		} catch (ClientProtocolException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	/**
	 * 为uri进行加密,并进行表单提交;
	 * 
	 * 许多应用需要模拟提交的HTML表单的处理,例如,在
		为了登录到Web应用程序或提交的输入数据。 HttpClient提供的实体类
		UrlEncodedFormEntity可以实现该过程;
	 */
	private static void test2(){
		
		CloseableHttpClient client = HttpClients.createDefault();
		
		HttpPost httppost = new HttpPost("http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx/getMobileCodeInfo");
		
		//构建请求参数
		List<NameValuePair> list = new ArrayList<NameValuePair>();
		list.add(new BasicNameValuePair("mobileCode", "110"));
		list.add(new BasicNameValuePair("userID", ""));

		//构建url加密实体,并以utf-8方式进行加密;
		UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, Consts.UTF_8);
		httppost.setEntity(entity);
		
		try {
			CloseableHttpResponse response = client.execute(httppost);
			
			if(response.getStatusLine().getStatusCode()==200){
				
				//org.apache.http.util.EntityUtils类可以快速处理服务器返回实体对象
				System.out.println(EntityUtils.toString(response.getEntity()));
				
			}
		} catch (ClientProtocolException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	
	}
	
	
	/**
	 * 以回调方式处理返回结果
	 * 
	 *  处理响应的最简单和最方便的方法是通过使用ResponseHandler的
		接口。用户不必担心连接管理的问题。当使用一个
		ResponseHandler的时候,无论是否请求执行成功或导致异常,HttpClient将会自动释放连接。
	 */
	private static void test3(){
		
		CloseableHttpClient client = HttpClients.createDefault();
		
		//==============================================================
		ResponseHandler<Object> handler = new ResponseHandler<Object>() {
			@Override
			public Object handleResponse(final HttpResponse response) throws IOException {
				
				HttpEntity entity = response.getEntity();
				
				if (entity == null) {
					throw new ClientProtocolException("返回结果为空");
				}
			
				if(response.getStatusLine().getStatusCode()==200){
					
					//获取返回结果的字符集 如:utf-8  gbk,并以这种字符集来读取流信息
					ContentType contentType = ContentType.getOrDefault(entity);
					Charset charset = contentType.getCharset();
					
					InputStreamReader reader = new InputStreamReader(entity.getContent(), charset);
					BufferedReader br = new BufferedReader(reader);
					StringBuffer sb = new StringBuffer();
					char[] buffer = new char[1024];
					while (br.read(buffer)!=-1) {
						sb.append(new String(buffer));
					}
					
					return sb.toString();
				}
				
				return null;
				
			}
		};
		//===================================================================
		
		URI uri = null;//构建uri实体
		try {
			uri = new URIBuilder()
			.setScheme("http")
			.setHost("webservice.webxml.com.cn")
			.setPath("/WebServices/MobileCodeWS.asmx/getDatabaseInfo")
			.setParameter("", "")
			.setParameter("", "")
			.setParameter("", "")
			.build();
			
		} catch (URISyntaxException e) {
			e.printStackTrace();
		}
		
		HttpPost post = new HttpPost(uri);
		
		try {
			
			//handler回调
			 Object obj = client.execute(post, handler);
			 
			 System.out.println("返回结果:"+obj);
			
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	
	
	
	/**
	 * 	设置长连接策略,根据服务器的约束或者客户端的约束来设置长连接的时长;
	 */
	private static void test4() {
		
		ConnectionKeepAliveStrategy strategy = new DefaultConnectionKeepAliveStrategy() {
			
			/**
			 * 服务器端配置(以tomcat为例):keepAliveTimeout=60000,表示在60s内内,服务器会一直保持连接状态。
			 * 也就是说,如果客户端一直请求服务器,且间隔未超过60s,则该连接将一直保持,如果60s内未请求,则超时。
			 * 
			 * getKeepAliveDuration返回超时时间;
			 */
			@Override
			public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
				
				
				//如果服务器指定了超时时间,则以服务器的超时时间为准
		        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("timeout")) {
						try {
							System.out.println("服务器指定的超时时间:" + value + " 秒");
							return Long.parseLong(value) * 1000;
						} catch (NumberFormatException ignore) {
							ignore.printStackTrace();
						}
					}
				}
		        
		        
		        long keepAlive = super.getKeepAliveDuration(response, context);
				
				 // 如果服务器未指定超时时间,则客户端默认30s超时
				if (keepAlive == -1) {
					keepAlive = 30 * 1000;
				}
		        
				return keepAlive;
		        
		        /*如果访问webservice.webxml.com.cn主机,则超时时间5秒,其他主机超时时间30秒
		        HttpHost host = (HttpHost) context.getAttribute(HttpClientContext.HTTP_TARGET_HOST);
		        if ("webservice.webxml.com.cn".equalsIgnoreCase(host.getHostName())) {
		        	keepAlive =  10 * 1000;
		        } else {
		        	keepAlive =  30 * 1000;
		        }*/
		        
		        
			}
		};
		
		
		
		CloseableHttpClient client = HttpClients.custom().setKeepAliveStrategy(strategy).build();
		
		URI uri = null;//构建uri实体
		try {
			uri = new URIBuilder()
			.setScheme("http")
			.setHost("webservice.webxml.com.cn")
			.setPath("/WebServices/MobileCodeWS.asmx/getDatabaseInfo")
			.setParameter("", "")
			.build();
			
		} catch (URISyntaxException e) {
			e.printStackTrace();
		}
		
		HttpPost post = new HttpPost(uri);
		
		try {
			
			CloseableHttpResponse response =  client.execute(post);
			if(response.getStatusLine().getStatusCode()==200){
				String result = EntityUtils.toString(response.getEntity());
				System.out.println("返回的结果====="+result);
			}
			
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	
		
	}
	
	
	/**
	 * 构建复杂请求体
	 * 
	 * RequestConfig将会保存在context上下文中,并会在连续的请求中进行传播(来自官方文档);
	 * 
	 */
	private void test5(){

		
		CloseableHttpClient client = HttpClients.createDefault();
		
		//构建请求配置
		RequestConfig config = RequestConfig.
				custom().
				setSocketTimeout(1000*10).
				setConnectTimeout(1000*10).
				build();
		//==============================================================
		ResponseHandler<Object> handler = new ResponseHandler<Object>() {//回调
			@Override
			public Object handleResponse(final HttpResponse response) throws IOException {
				
				HttpEntity entity = response.getEntity();
				
				if (entity == null) {
					throw new ClientProtocolException( "返回结果为空");
				}
			
				if(response.getStatusLine().getStatusCode()==200){
					ContentType contentType = ContentType.getOrDefault(entity);
					Charset charset = contentType.getCharset();
					
					InputStreamReader reader = new InputStreamReader(entity.getContent(), charset);
					BufferedReader br = new BufferedReader(reader);
					StringBuffer sb = new StringBuffer();
					char[] buffer = new char[1024];
					while (br.read(buffer)!=-1) {
						sb.append(new String(buffer));
					}
					
					return sb.toString();
				}
				
				return null;
				
			}
		};
		//===================================================================
		
		URI uri = null;
		try {
			uri = new URIBuilder()
			.setScheme("http")
			.setHost("webservice.webxml.com.cn")
			.setPath("/WebServices/MobileCodeWS.asmx/getDatabaseInfo")
			.setParameter("", "")
			.setParameter("", "")
			.setParameter("", "")
			.build();
			
		} catch (URISyntaxException e) {
			e.printStackTrace();
		}
		
		HttpPost post = new HttpPost(uri);
		
		post.setConfig(config);//设置请求配置
		
		try {
			 Object obj = client.execute(post, handler);
			 
			 System.out.println("返回结果:"+obj);
			
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	
	}
	
	
	
	/**
	 *  异常恢复机制:
	 *  
	 *  HttpRequestRetryHandler连接失败后,可以针对相应的异常进行相应的处理措施;
	 *  HttpRequestRetryHandler接口须要用户自己实现;
	 *  
	 */
	private static  void test6(){

		HttpRequestRetryHandler retryHandler = new HttpRequestRetryHandler() {
			
			/**
			 * exception异常信息;
			 * executionCount:重连次数;
			 * context:上下文
			 */
			@Override
			public boolean retryRequest(IOException exception, int executionCount,HttpContext context) {

				System.out.println("重连接次数:"+executionCount);
				
				if (executionCount >= 5) {//如果连接次数超过5次,就不进行重复连接
					return false;
				}
				if (exception instanceof InterruptedIOException) {//io操作中断
					return false;
				}
				if (exception instanceof UnknownHostException) {//未找到主机
					// Unknown host
					return false;
				}
				if (exception instanceof ConnectTimeoutException) {//连接超时
					return true;
				}
				if (exception instanceof SSLException) {
					// SSL handshake exception
					return false;
				}
				HttpClientContext clientContext = HttpClientContext.adapt(context);
				
				HttpRequest request = clientContext.getRequest();
				
				boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
				
				if (idempotent) {
					// Retry if the request is considered idempotent
					return true;
				}
				return false;
			}
		};
		
		
		CloseableHttpClient client = HttpClients.custom().setRetryHandler(retryHandler).build();
		
		RequestConfig config = RequestConfig.
				custom().
				setSocketTimeout(1000*10).
				setConnectTimeout(1000*10).
				build();
		
		HttpPost post = new HttpPost("http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx/getDatabaseInfo");
		
		post.setConfig(config);
		
		try {
			HttpResponse response = client.execute(post);
			HttpEntity entity = response.getEntity();
			
			ContentType contentType = ContentType.getOrDefault(entity);
			Charset charset = contentType.getCharset();

			InputStreamReader reader = new InputStreamReader(entity.getContent(), charset);
			BufferedReader br = new BufferedReader(reader);
			StringBuffer sb = new StringBuffer();
			char[] buffer = new char[1024];
			while (br.read(buffer) != -1) {
				sb.append(new String(buffer));
			}

			System.out.println("返回的结果:"+sb.toString());

		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	
	
	/**
	 * 	HTTP请求过滤器,在执行请求之前拦截HttpRequest 和 HttpContext;
	 */
	private static void test7() throws ClientProtocolException, IOException{
		
		HttpRequestInterceptor requestInterceptor = new HttpRequestInterceptor() {
			/**
			 * 处理请求:
			 * 如果是客户端:这个处理在发送请求之前执行;
			 * 如果是服务器:这个处理在接收到请求体之前执行;
			 */
			public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException {
				AtomicInteger count = (AtomicInteger) context.getAttribute("count");
				request.addHeader("count", Integer.toString(count.getAndIncrement()));
			}
		};
		
		
		CloseableHttpClient httpclient = HttpClients.
						custom().
						addInterceptorLast(requestInterceptor).
						build();
		
		
		AtomicInteger count = new AtomicInteger(1);
		HttpClientContext context = HttpClientContext.create();
		context.setAttribute("count", count);
		HttpGet httpget = new HttpGet("http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx/getDatabaseInfo");
		
		for (int i = 0; i < 10; i++) {
			CloseableHttpResponse response = httpclient.execute(httpget,context);
			try {
				
				HttpEntity entity = response.getEntity();
//				System.out.println(EntityUtils.toString(entity));
				
			} finally {
				response.close();
			}
		}
	}
	
	
	
	
	/**
	 * 
	 *  httpclient会自动处理重定向; 
	 *  
	 *  301 永久重定向,告诉客户端以后应从新地址访问.
		302 作为HTTP1.0的标准,以前叫做Moved Temporarily ,现在叫Found. 现在使用只是为了兼容性的  处理,包括PHP的默认Location重定向用的也是302.
		但是HTTP 1.1 有303 和307作为详细的补充,其实是对302的细化
		303:对于POST请求,它表示请求已经被处理,客户端可以接着使用GET方法去请求Location里的URI。
		307:对于POST请求,表示请求还没有被处理,客户端应该向Location里的URI重新发起POST请求。
	 */
	private static void test8() throws ClientProtocolException, IOException,
			URISyntaxException {

		LaxRedirectStrategy redirectStrategy = new LaxRedirectStrategy();
		CloseableHttpClient httpclient = HttpClients.custom().setRedirectStrategy(redirectStrategy).build();

		HttpClientContext context = HttpClientContext.create();
		HttpGet httpget = new HttpGet("http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx/getDatabaseInfo");
		CloseableHttpResponse response = httpclient.execute(httpget, context);
		try {
			HttpHost target = context.getTargetHost();
			List<URI> redirectLocations = context.getRedirectLocations();
			URI location = URIUtils.resolve(httpget.getURI(), target, redirectLocations);
			System.out.println("Final HTTP location: " + location.toASCIIString());
		} finally {
			response.close();
		}
	}
	
	
	
	
}


JAVA: httpclient 详解;,布布扣,bubuko.com

JAVA: httpclient 详解;

标签:java   httpclient   http协议   

原文地址:http://blog.csdn.net/lyc66666666666/article/details/36899463

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!