JAVA: httpclient 详解

来源:互联网 发布:mac磁盘工具找不到硬盘 编辑:程序博客网 时间:2024/05/22 11:49

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 blocke.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/getDatabaseInfoHttpGet 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 blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.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 blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}/** * 以回调方式处理返回结果 *  *  处理响应的最简单和最方便的方法是通过使用ResponseHandler的接口。用户不必担心连接管理的问题。当使用一个ResponseHandler的时候,无论是否请求执行成功或导致异常,HttpClient将会自动释放连接。 */private static void test3(){CloseableHttpClient client = HttpClients.createDefault();//==============================================================ResponseHandler<Object> handler = new ResponseHandler<Object>() {@Overridepublic 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返回超时时间; */@Overridepublic 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>() {//回调@Overridepublic 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:上下文 */@Overridepublic 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 hostreturn false;}if (exception instanceof ConnectTimeoutException) {//连接超时return true;}if (exception instanceof SSLException) {// SSL handshake exceptionreturn false;}HttpClientContext clientContext = HttpClientContext.adapt(context);HttpRequest request = clientContext.getRequest();boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);if (idempotent) {// Retry if the request is considered idempotentreturn 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();}}}

0 0