httpclient的使用(二)
一、HTTP context的使用
HTTP协议是无状态的协议,但是在使用时,我们总希望一些状态信息能够更长的时间,我们称之为上下文。我们可以采用以下方式为我们的会话增加状态信息。
1 HttpContext httpContext = new BasicHttpContext(); 2 HttpGet httpGet = <...> 3 HttpResponse response = httpClient.execute(httpGet, httpContext);
HttpClient提供了一下属性可以添加到我们中会话中,这是属性以键值对的方式存在于context中
- HttpConnection
- HttpHost
- HttpRoute
- HttpRequest
- HttpResponse
- java.lang.Boolean
- RequestConfig
- java.util.List<URI>
下面的代码是增加RequestConfig属性
1 CloseableHttpClient httpclient = HttpClients.createDefault(); 2 RequestConfig requestConfig = RequestConfig.custom() 3 .setSocketTimeout(1000) 4 .setConnectTimeout(1000) 5 .build(); 6 HttpGet httpget1 = new HttpGet("http://localhost/1"); 7 httpget1.setConfig(requestConfig); 8 CloseableHttpResponse response1 = httpclient.execute(httpget1, context); 9 try { 10 HttpEntity entity1 = response1.getEntity(); 11 } finally { 12 response1.close(); 13 } 14 HttpGet httpget2 = new HttpGet("http://localhost/2"); 15 CloseableHttpResponse response2 = httpclient.execute(httpget2, context); 16 try { 17 HttpEntity entity2 = response2.getEntity(); 18 } finally { 19 response2.close(); 20 }
context测试样例
1 package download.test; 2 3 import java.io.IOException; 4 5 import org.apache.http.HttpEntity; 6 import org.apache.http.HttpHost; 7 import org.apache.http.HttpResponse; 8 import org.apache.http.client.ClientProtocolException; 9 import org.apache.http.client.methods.HttpGet; 10 import org.apache.http.client.methods.HttpUriRequest; 11 import org.apache.http.client.protocol.HttpClientContext; 12 import org.apache.http.entity.ContentType; 13 import org.apache.http.impl.client.CloseableHttpClient; 14 import org.apache.http.impl.client.HttpClients; 15 import org.apache.http.protocol.BasicHttpContext; 16 import org.apache.http.protocol.HttpContext; 17 import org.apache.http.util.EntityUtils; 18 19 public class Download { 20 21 public static void main(String[] args) throws ClientProtocolException, 22 IOException { 23 /** 24 * 获取重定向之后的网址信息 25 * 26 * @see HttpClient缺省会自动处理客户端重定向 27 * @see 即访问网页A后,假设被重定向到了B网页,那么HttpClient将自动返回B网页的内容 28 * @see 若想取得B网页的地址 29 * ,就需要借助HttpContext对象,HttpContext实际上是客户端用来在多次请求响应的交互中,保持状态信息的 30 * @see 我们自己也可以利用HttpContext来存放一些我们需要的信息,以便下次请求的时候能够取出这些信息来使用 31 */ 32 33 CloseableHttpClient httpClient = HttpClients.createDefault(); 34 HttpContext httpContext = new BasicHttpContext(); 35 HttpGet httpGet = new HttpGet("http://127.0.0.1:80/"); 36 try { 37 // 将HttpContext对象作为参数传给execute()方法,则HttpClient会把请求响应交互过程中的状态信息存储在HttpContext中 38 HttpResponse response = httpClient.execute(httpGet, httpContext); 39 // 将httpContext放入到适配器中以方便访问 40 HttpClientContext clientContext = HttpClientContext 41 .adapt(httpContext); 42 HttpHost targetHost = clientContext.getTargetHost(); 43 // 获取实际的请求对象的URI 44 HttpUriRequest realRequest = (HttpUriRequest) clientContext.getRequest(); 45 // .getRequest(); 46 System.out.println("主机地址:" + targetHost); 47 System.out.println("URI信息:" + realRequest.getURI()); 48 HttpEntity entity = response.getEntity(); 49 if (null != entity) { 50 System.out.println("响应内容:" 51 + EntityUtils.toString(entity, ContentType 52 .getOrDefault(entity).getCharset())); 53 EntityUtils.consume(entity); 54 } 55 } catch (Exception e) { 56 e.printStackTrace(); 57 } finally { 58 httpClient.close();; 59 } 60 } 61 }
二、HTTP拦截器的使用
HTTP拦截器可以对特定的请求、应答甚至页面进行处理,也能通过HTTP上下文环境进行信息共享,如果多个拦截器协同工作时要考虑执行顺序的问题。
下面的例子是将本地context的信息添加到所有的请求头中
1 CloseableHttpClient httpclient = HttpClients.custom() 2 .addInterceptorLast(new HttpRequestInterceptor() { 3 public void process( 4 final HttpRequest request, 5 final HttpContext context) throws HttpException, IOException { 6 AtomicInteger count = (AtomicInteger) context.getAttribute("count"); 7 request.addHeader("Count", Integer.toString(count.getAndIncrement())); 8 } 9 }) 10 .build(); 11 AtomicInteger count = new AtomicInteger(1); 12 HttpClientContext localContext = HttpClientContext.create(); 13 localContext.setAttribute("count", count); 14 HttpGet httpget = new HttpGet("http://localhost/"); 15 for (int i = 0; i < 10; i++) { 16 CloseableHttpResponse response = httpclient.execute(httpget, localContext); 17 try { 18 HttpEntity entity = response.getEntity(); 19 } finally { 20 response.close(); 21 } 22 }
三、请求retry操作
在发起http请求时可能因为网络拥塞等原因,使得发送失败,这时我们会尝试重新发送请求。
1 HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() { 2 public boolean retryRequest( 3 IOException exception, 4 int executionCount, 5 HttpContext context) { 6 if (executionCount >= 5) { 7 // Do not retry if over max retry count 8 return false; 9 } 10 if (exception instanceof InterruptedIOException) { 11 // Timeout 12 return false; 13 } 14 if (exception instanceof UnknownHostException) { 15 // Unknown host 16 return false; 17 } 18 if (exception instanceof ConnectTimeoutException) { 19 // Connection refused 20 return false; 21 } 22 if (exception instanceof SSLException) { 23 // SSL handshake exception 24 return false; 25 } 26 HttpClientContext clientContext = HttpClientContext.adapt(context); 27 HttpRequest request = clientContext.getRequest(); 28 boolean idempotent = !(request instanceof HttpEntityEnclosingRequest); 29 if (idempotent) { 30 // Retry if the request is considered idempotent 31 return true; 32 } 33 return false; 34 } 35 }; 36 CloseableHttpClient httpclient = HttpClients.custom() 37 .setRetryHandler(myRetryHandler) 38 .build();