HttpClient4.5-第一章基础

HTTP协议相关
httpclient:只是传输和接收http请求。
最简单的请求例子:

CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpget = new HttpGet("http://localhost/");
CloseableHttpResponse response = httpclient.execute(httpget);
try {
    <...>
} finally { 
   response.close();
}

HttpClient提供UriBuilder类来简化创建和修改请求的URI。

URI uri = newURIBuilder()
.setScheme("http").setHost("www.google.com").setPath("/search")
.setParameter("q", "httpclient").setParameter("btnG", "Google Search").setParameter("aq", "f").setParameter("oq", "").build();
HttpGet httpget = new HttpGet(uri);
System.out.println(httpget.getURI());
//-->http://www.google.com/search?q=httpclient&btnG=Google+Search&aq=f&oq=

Http响应Response:

HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
System.out.println(response.getProtocolVersion());
//HTTP/1.1
System.out.println(response.getStatusLine().getStatusCode());//200
System.out.println(response.getStatusLine().getReasonPhrase());//OK
System.out.println(response.getStatusLine().toString());
//HTTP/1.1 200 OK

HttpHeader:
HTTP消息可以包含许多消息头,描述消息的属性,如内容长度、内容类型等。HttpClient提供遍历,添加方法,删除等操作方法。

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);
  //Set-Cookie: c1=a; path=/; domain=localhost
        Header h2 = response.getLastHeader("Set-Cookie");
        System.out.println(h2);
 //Set-Cookie: c2=b; path="/", c3=c; domain="localhost"
        Header[] hs = response.getHeaders("Set-Cookie");
        System.out.println(hs.length);//2

也可以利用 HeaderIterator接口来遍历Header:

        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\"");
        HeaderIterator it = response.headerIterator("Set-Cookie");
        while (it.hasNext()) {
            System.out.println(it.next());
        }

输出:
Set-Cookie: c1=a; path=/; domain=localhost
Set-Cookie: c2=b; path=”/”, c3=c; domain=”localhost”


HTTP entity
HTTP消息可以携带一个请求和响应的内容关联实体。实体可以在部分请求和部分响应中得到,因为它们是可选的。实体的分类:

  1. streamed:从response的流中得到,通常不可重复
  2. self-contained:从内存中获得,主要用于封装请求实体,通常可重复
  3. wrapping:内容从其他实体中获得

注意:只有自包含实体可以重复例如:ByteArrayEntity ,StringEntity
使用:

StringEntity myEntity = new StringEntity("important message",
ContentType.create("text/plain", "UTF-8"));
System.out.println(myEntity.getContentType());
System.out.println(myEntity.getContentLength());
try {          System.out.println(EntityUtils.toString(myEntity));         System.out.println(EntityUtils.toByteArray(myEntity).length);
} catch (IOException e) {
     e.printStackTrace();
}

输出:

Content-Type: text/plain; charset=UTF-8
17
important message
17

注意:为了确保适当释放系统资源,必须关闭与实体或响应本身相关联的内容流。

CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpGet httpget = new HttpGet("http://localhost/");
        CloseableHttpResponse response = httpclient.execute(httpget);
        try {
            HttpEntity entity = response.getEntity();
            InputStream instream = null;
            if (entity != null) {
                instream = entity.getContent();
            }
            try {
                // do something useful
            } finally {
                instream.close();
            }
    } finally {
        response.close();
    }

关闭内容流和关闭响应的区别:
前者试图通过消耗实体内容来维持底层连接,
而后者立即关闭并丢弃连接。

官方推荐使用实体的方式:
HttpEntity#getContent()
HttpEntity#writeTo(OutputStream)

CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpget = new HttpGet("http://localhost/");
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 {
                   // Stream content out
                }
        }
} finally {
    response.close();
}

在某些情况下,可能需要不止一次地读取实体内容。在这种情况下,实体内容必须以某种方式进行缓冲,无论是在内存中还是在磁盘上。完成,最简单的方法是用bufferedhttpentity包装实体。这将使原始实体的内容被读入内存缓冲区。

CloseableHttpResponse response = <...>
HttpEntity entity = response.getEntity();
if (entity != null) {
    entity = new BufferedHttpEntity(entity);
}

HttpClient 提供了常用的实体类:StringEntity,ByteArrayEntity,InputStreamEntity, FileEntity
InputStreamEntity是不可以重复的,只能读取底层数据一次

File file = new File("somefile.txt");
FileEntity entity = new FileEntity(file,ContentType.create("text/plain", "UTF-8"));
HttpPost httppost = new HttpPost("http://localhost/action.do");
httppost.setEntity(entity);

HTML表单
许多应用程序需要模拟提交HTML表单的过程,例如登录Web应用程序或提交输入数据。HttpClient提供实体UrlEncodedFormEntity

List<NameValuePair> formparams = new ArrayList<NameValuePair>();
formparams.add(new BasicNameValuePair("param1", "value1"));
formparams.add(new BasicNameValuePair("param2", "value2"));
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams, Consts.UTF_8);
HttpPost httppost = new HttpPost("http://localhost/handler.do");
httppost.setEntity(entity);

结果:param1=value1&param2=value2
内容分块:
设置 HttpEntity#setChunked()方法为true是通知HttpClient分块编码的首选。请注意HttpClient将会使用标识作为提示。当使用的HTTP协议版本,如HTTP/1.0版本,不支持分块编码时,这个值会被忽略。

StringEntity entity = new StringEntity("important message",ContentType.create("plain/text", Consts.UTF_8));
entity.setChunked(true);
HttpPost httppost = new HttpPost("http://localhost/acrtion.do");
httppost.setEntity(entity);

响应控制器
控制响应的最简便和最方便的方式是使用ResponseHandler接口。这个放完完全减轻了用户关于连接管理的担心。当使用ResponseHandler时,HttpClient将会自动关注并保证释放连接到连接管理器中去,而不管请求执行是否成功或引发了异常。

HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet("http://localhost/");
ResponseHandler<byte[]> handler = new ResponseHandler<byte[]>() {
    public byte[] handleResponse(
        HttpResponse response) throws ClientProtocolException, IOException {
        HttpEntity entity = response.getEntity();
        if (entity != null) {
            return EntityUtils.toByteArray(entity);
        } else {
            return null;
        }
    }
};
byte[] response = httpclient.execute(httpget, handler);

当CloseableHttpClient不再使用时,必须进行关闭。

CloseableHttpClient httpclient=HttpClients.createDefault();
try {    <...>} finally {    httpclient.close();}

HTTP执行的环境
最初,HTTP是被设计成无状态的,面向请求-响应的协议。然而,应用程序经常需要通过一些逻辑相关的请求-响应交换来持久状态信息。HttpClient允许HTTP请求在一个特定的执行环境中来执行,简称为HTTP上下文。HTTP上下文功能和java.util.Map很相似。 它仅仅是任意命名参数值的集合。
在HTTP请求执行的这一过程中,HttpClient添加了下列属性到执行上下文中:
‘http.connection’:HttpConnection实例代表了连接到目标服务器的真实连接。
‘http.target_host’:HttpHost实例代表了连接目标。
‘http.proxy_host’:如果使用了,HttpHost实例代表了代理连接。
‘http.request’:HttpRequest实例代表了真实的HTTP请求。
‘http.response’:HttpResponse实例代表了真实的HTTP响应。
‘http.request_sent’:java.lang.Boolean对象代表了暗示真实请求
‘RequestConfig’:实际的配置
‘java.util.List’:表示请求执行过程中接收到的所有重定向地址的集合
是否被完全传送到目标连接的标识。
比如,为了决定最终的重定向目标,在请求执行之后,可以检查http.target_host属性的值:

DefaultHttpClient httpclient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpGet httpget = new HttpGet("http://www.google.com/");
HttpResponse response = httpclient.execute(httpget, localContext);
HttpHost target = (HttpHost) localContext.getAttribute(
ExecutionContext.HTTP_TARGET_HOST);
System.out.println("Final target: " + target);
HttpEntity entity = response.getEntity();
if (entity != null) {
    entity.consumeContent();
}

请求重试处理
为了开启自定义异常恢复机制,应该提供一个HttpRequestRetryHandler接口的实现。

HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() {
public boolean retryRequest(IOException exception,
    int executionCount,HttpContext context) {
        if (executionCount >= 5) {
            // 如果超过最大重试次数,那么就不要继续了
            return false;
        }
        if (exception instanceof NoHttpResponseException) {
            // 如果服务器丢掉了连接,那么就重试
            return true;
        }
        if (exception instanceof SSLHandshakeException) {
            // 不要重试SSL握手异常
            return false;
        }
        HttpRequest request = (HttpRequest) context.getAttribute(
            ExecutionContext.HTTP_REQUEST);
        boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
        if (idempotent) {
            // 如果请求被认为是幂等的,那么就重试
            return true;
        }
        return false;
    }
};
CloseableHttpClient httpclient = HttpClients.custom().setRetryHandler(myRetryHandler).build();

中止请求
被HttpClient执行的HTTP请求可以在执行的任意阶段通过调用HttpUriRequest#abort()方 法而中止。这个方法是线程安全的,而且可以从任意线程中调用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值