一、基本的使用
HttpClient组件(这里以HttpClient4.3为例)可以模拟浏览器Http协议的request/response请求的交互。
下面的代码是基本使用的代码示例:
String url= "http://.......";
// 构建请求参数
CloseableHttpClient httpclient=HttpClients.createDefault();
HttpGet httpget=new HttpGet(url);
CloseableHttpResponse response=httpclient.execute(httpget);
try {
HttpEntity entity=response.getEntity();
InputStream in=entity.getContent();
if(in!=null){
//......
}
//...........
} finally {
response.close();
}
}
HttpClient是线程安全的,推荐在类中相同的实例在多线程中重复使用
1、HTTP request
httpClient支持HTTP1.1协议中的GET,HEAD,POST,PUT,DELETE,TRACE以及OPTIONS。分别对应如下的类:HttpGet,HttpHead,HttpPost,HttpPut,HttpDelete,HttpTrace以及HttpOptions.
HTTP 请求的URI由protocol scheme,hostname,optional port,resource path,optional query 和其他可选的部分组成
HttpClient提供了URI的构建工具类URIBuilder.使用方法如下:
URI uri=new URIBuilder().setScheme("http")
.setHost("www.google.com")
.setPath("/search")
.setParameter("q", "httpclient")
.setParameter("aq", "f")
.build();
System.out.println(uri.toString());
执行结果:http://www.google.com/search?q=httpclient&aq=f
2、HTTP Response
reponse是服务器收到并解析request之后返回给请求端的信息。
HttpResponse response=new BasicHttpResponse(HttpVersion.HTTP_1_1,HttpStatus.SC_OK,"OK");
System.out.println(response.getProtocolVersion());
System.out.println(response.getStatusLine().getStatusCode());
System.out.println(response.getStatusLine().getReasonPhrase());
System.out.println(response.getStatusLine().toString());
执行结果:
HTTP/1.1
200
OK
HTTP/1.1 200 OK
3、Http的请求头
HttpResponse response=new BasicHttpResponse(HttpVersion.HTTP_1_1,HttpStatus.SC_OK,"OK");
response.addHeader("Set-Cookie","c1=a;path=/;domain=localhost");
response.addHeader("Set-Cookie", "c2=b;path=\"/\",c3=c;domain=\"localhost\"");
Header h1=response.getFirstHeader("Set-Cookie");
System.out.println(h1);
Header h2=response.getLastHeader("Set-Cookie");
System.out.println(h2);
Header[] hs=response.getHeaders("Set-Cookie");
System.out.println(hs.length);
//最方便获取请求头属性的方式
HeaderIterator it=response.headerIterator("Set-Cookie");
while(it.hasNext()){
System.out.println(it.next());
}
HeaderElementIterator it=new BasicHeaderElementIterator(response.headerIterator("Set-Cookie"));
while(it.hasNext()){
HeaderElement elem=it.nextElement();
System.out.println(elem.getName()+" = " +elem.getValue());
NameValuePair[] params=elem.getParameters();
for(int i=0;i<params.length;i++){
System.out.println(" "+params[i]);
}
}
4、HTTP entity
主要是response返回内容的实体或者是request的时候使用post或者put方式的时候用到entity.
主要方法,HttpEntity entity=response.getEntity(); InputStream in=entity.getContent();
获取entity内容推荐的方式为HttpEntity#getContent()或者HttpEntity#writeTo(outputStream).
HttpClient也提供了工具类EntityUtils.java。但是只在信任返回来源且确切知道来源长度较小的情况下
推荐使用。
String url= "http://........";
// 构建请求参数
CloseableHttpClient httpclient=HttpClients.createDefault();
HttpGet httpget=new HttpGet(url);
CloseableHttpResponse response=httpclient.execute(httpget);
try {
HttpEntity entity=response.getEntity();
if(entity!=null){
long len=entity.getContentLength();
//当返回值长度较小的时候,使用工具类
if(len!=-1&&len<2048){
System.out.println(EntityUtils.toString(entity));
}else{
//否则使用IO流来读取
}
}
} finally {
response.close();
}
有时候需要重复多次获取entity,则需要用到包装类BufferedHttpEntity.java.代码示例如下:
HttpEntity entity=response.getEntity();
if(entity!=null){
entity=new BufferedHttpEntity(entity);
}
构建Entity的方式有多种数据形式,比如,string,byte array,input stream,file等。分别对应如下类,StringEntity,ByteArrayEntity,InputStreamEntity,FileEntity.代码示例如下:
File file=new File("somefile.txt");
FileEntity entity=new FileEntity(file);
HttpPost httppost=new HttpPost("http://localhost/.../action.do");
httppost.setEntity(entity);
5、模拟HTML forms提交
List<NameValuePair> formparams=new ArrayList<NameValuePair>();
formparams.add(new BasicNameValuePair("param1", "value1"));
formparams.add(new BasicNameValuePair("param2", "value2"));
formparams.add(new BasicNameValuePair("param3", "value3"));
UrlEncodedFormEntity entity=new UrlEncodedFormEntity(formparams,Consts.UTF_8);
HttpPost httppost=new HttpPost("http://localhost/handler.do");
httppost.setEntity(entity);
6、Response Handlers
ResponseHandler,.....
7、针对幂等的请求,自定义重试机制的handler
//自定义重试机制
HttpRequestRetryHandler myRetryHandler=new HttpRequestRetryHandler(){
public boolean retryRequest(IOException exception,
int executionCount, HttpContext context) {
if (executionCount >= 5) {
// Do not retry if over max retry count
return false;
}
if (exception instanceof InterruptedIOException) {
// Timeout
return false;
}
if (exception instanceof UnknownHostException) {
// Unknown host
return false;
}
if (exception instanceof ConnectTimeoutException) {
// Connection refused
return false;
}
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 httpclient = HttpClients.custom()
.setRetryHandler(myRetryHandler)
.build();
}
8、HttpClient的拦截器(interceptor)
类似于servlet,需要自己保证线程安全。
代码示例:
//http拦截器
CloseableHttpClient httpclient = HttpClients.custom()
.addInterceptorLast(new HttpRequestInterceptor() {
public void process(
final HttpRequest request,
final HttpContext context) throws HttpException, IOException {
AtomicInteger count = (AtomicInteger) context.getAttribute("count1");
request.addHeader("count1", Integer.toString(count.getAndIncrement()));
}
}).build();
AtomicInteger count = new AtomicInteger(1);
HttpClientContext localContext = HttpClientContext.create();
localContext.setAttribute("count1", count);
localContext.setAttribute("count2", count);
HttpGet httpget = new HttpGet(url);
for (int i = 0; i < 10; i++) {
CloseableHttpResponse response = httpclient.execute(httpget, localContext);
try {
HttpEntity entity = response.getEntity();
//.....
} finally {
response.close();
}
}
}
9、重定向的Handler
httpcomponents 在处理重定向问题时,默认的情况下是有限制的:
对于 HEAD 和 GET 方法, HttpComponents 会自动做重定向处理;
对于 POST 和 PUT 方法, HttpComponents 不会进行自动重定向处理,这需要用户自己设定才行。
DefaultHttpClient client = new DefaultHttpClient();
LaxRedirectStrategy redirectStrategy = new LaxRedirectStrategy();
// 设定自己需要的重定向策略
client.setRedirectStrategy(redirectStrategy);
// 创建登陆form
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
formparams.add(new BasicNameValuePair("username", USERNAME));
formparams.add(new BasicNameValuePair("password", PASSWORD));
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(formparams, "UTF-8");
// 创建登陆请求
HttpPost loginPost = new HttpPost(URL_LOGIN);
loginPost.setEntity(formEntity);
// 执行请求,
// 在使用默认的重定向策略是,状态代码返回的是 302
// 使用了重定向策略后, 状态代码返回的是 200
HttpResponse loginResponse = client.execute(loginPost);
System.out.println("登录请求放回状态代码: " + loginResponse.getStatusLine().getStatusCode());
获取重定向的URI以及还原之后的URL:
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpClientContext context = HttpClientContext.create();
HttpGet httpget = new HttpGet(url);
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());
// Expected to be an absolute URI
} finally {
response.close();
}