HttpClient4.5学习梳理以及验证

致敬大神:http://blog.csdn.net/column/details/httpclient.htmljavascript

如下只是对大神做品学习以及验证:html

《一》明白HttpClient可以作什么,这个很重要java

        超文本传输协议(HTTP)也许是当今互联网上所使用的最重要的协议了。Web services,联网设备和网络计算的发展,都持续扩展了HTTP协议的角色,超越了用户使用的Web浏览器范畴,同时,也增长了须要HTTP协议支持的应用程序的数量。
      尽管java.net包提供了经过HTTP访问资源的基本功能,但它缺乏足够的灵活性和其它不少应用程序须要的功能。HttpClient经过提供一个有效的,保持更新的,功能丰富的软件包来实现客户端最新的HTTP标准和建议,来弥补java.net包的在某些技术上的空白。 
         HttpClient为扩展而设计,同时为基本的HTTP协议提供强大的支持。有一些人会对HttpClient感兴趣,这些人一般是构建 HTTP 客户端应用程序(好比web浏览器,web服务客户端,利用或扩展 HTTP 协议进行来实现的分布式通讯系统)的开发人员。
1.HttpClient 的范围
●基于HttpCore[http://hc.apache.org/httpcomponents-core/index.html]的客户端HTTP通讯库
●基于经典(阻塞) I/O
●内容无关   --我理解为不关注内容
2.HttpClient 所不能作的
●HttpClient 不是一个浏览器。它是一个客户端的 HTTP 通讯实现库。HttpClient 的目标是发送和接收HTTP 报文。HttpClient 不会去处理内容,执行嵌入在 HTML页面中的javascript 代码,猜想内容类型,若是没有明确设置,不然不会从新格式化请求/重定向URI,或其它和HTTP通讯无关的功能。web

------------------------------------------------------------------------------------------------------apache

(1)HttpClient最基本的功能是执行HTTP方法;json

(2)一个 HTTP 方法的执行包含一个或多个 HTTP 请求/HTTP 相应的交换,一般由 HttpClient的内部来处理。数组

(3)使用者被要求提供一个Request对象来执行,HttpClient就会把请求传送给目标服务器并返回一个相对应的response对象,若是执行不成功,将会抛出一个异常。浏览器

--显然,HttpClient API 的主要切入点就是定义描述上述契约的HttpClient接口。缓存

下边就说服务器

1>什么是HTTP请求(Request对象)?

2>什么是HTTP相应的交换

3>HTTP报文

4>Request对象处理

5>Response对象处理

 

 

《1》什么是HTTP请求(Request对象)?

全部 HTTP 请求都有一个请求起始行,这个起始行由方法名,请求 URI 和 HTTP 协议版本组成。HttpClient很好地支持了HTTP/1.1规范中全部的HTTP方法:GET,HEAD, POST,PUT, DELETE, TRACE 和 OPTIONS。每一个方法都有一个特别的类:HttpGet,HttpHead, HttpPost,HttpPut,HttpDelete,HttpTrace和HttpOptions。URI是统一资源标识符的缩写,用来标识与请求相符合的资源。HTTP 请求URI包含了一个协议名称,主机名,可选端口,资源路径,可选的参数,可选的片断。

写法以下:

HttpGet httpget = new HttpGet(  

     "http://www.google.com/search?hl=en&q=httpclient&btnG=Google+Search&aq=f&oq=");

HttpClient提供了URIBuilder工具类来简化建立、修改请求 URI。

因此上边写法还能够改为

URI uri = new URIBuilder()  

          .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);

 

2>什么是HTTP相应的交换

HttpClient表明HTTP请求执行的最基本约定。它没有强加限制或具体细节给请求执行过程,它保留了链接管理,状态管理,认证,重定向等处理细节的我的实现。使用额外的功能来装饰这个接口是很是容易的,好比设置响应体缓存。

HttpClient实现做为特殊目的的处理器或策略接口的门面,负责处理HTTP协议特定的方面,好比重定向处理,认证处理,为链接持久化作决定或者保持持续链接。这使得用户使用自定义的、应用程序特定方面的实现来取代那些默认的实现。

这一块涉及不少细节,后边再单独一一列举讲解

 

3>HTTP报文

http报文专门单列出来说。。

 

 

4>Request对象处理(HTTP 响应(Response))

HTTP 响应是服务器接收并解析请求信息后返回给客户端的信息,它的起始行包含了一个协议版本,一个状态码和描述状态的短语。

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());  

 

处理报文首部(Headers)

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接口

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());  

}

HttpClient也提供了其余便利的方法吧HTTP报文转化为单个的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\"");  

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]);  

     }  

}

 

HTTP实体(HTTP Entity)

HTTP报文可以携带与请求或响应相关联的内容实体。

实体存在于某些请求、响应中,他们是可选的。

 

使用实体的请求被称为内含实体请求;HTTP规范定义了两种内含实体请求,POST和PUT。

而响应老是内含实体。但有些响应不符合这一规则,好比,对HEAD方法的响应和状态为204 No Content, 304 Not Modified, 205 Reset Content的响应。

 

依据实体的内容来源,HttpClient区分出三种实体:

流式实体(streamed):内容来源于一个流,或者在运行中产生。特别的,这个类别包括从响应中接收到的实体。流式实体不可重复。

自包含实体(self-contained):在内存中的内容或者经过独立的链接/其余实体得到的内容。自包含实体是可重复的。这类实体大部分是HTTP内含实体请求。

包装实体(wrapping):从另一个实体中获取内容

 

 

使用HTTP实体

因为一个实体可以表现为二进制和字符内容,它支持二进制编码(为了支持后者,即字符内容)。

实体将会在一些状况下被建立:当执行一个含有内容的请求时或者当请求成功,响应体做为结果返回给客户端时。为了读取实体的内容,能够经过HttpEntity#getContent() 方法取出输入流,返回一个java.io.InputStream,或者提供一个输出流给HttpEntity#writeTo(OutputStream) 方法,它将会返回写入给定流的全部内容。

当实体内部含有信息时,使用HttpEntity#getContentType()和HttpEntity#getContentLength()方法将会读取一些基本的元数据,好比Content-Type和Content-Length这样的首部(若是他们可用的话),因为Content-Type首部可以包含文本MIME类型(像 text/plain 或text/html),它也包含了与MIME类型相对应的字符编码,HttpEntity#getContentEncoding()方法被用来读取这些字符编码。若是对应的首部不存在,则Content-Length的返回值为-1,Content-Type返回值为NULL。若是Content-Type是可用的,一个Header类的对象将会返回。

 

当咱们构建一个具备可用信息的实体时,元数据将会被实体构建器提供。

StringEntity myEntity = new StringEntity("important message",  

                          ContentType.create("text/plain", "UTF-8"));  

System.out.println(myEntity.getContentType());  

System.out.println(myEntity.getContentLength());  

System.out.println(EntityUtils.toString(myEntity));  

System.out.println(EntityUtils.toByteArray(myEntity).length);

 

确保释放低级别的资源

为了确保正确的释放系统资源,你必须关掉与实体与实体相关的的内容流,还必须关掉响应自己。

CloseableHttpClient httpclient = HttpClients.createDefault();  

HttpGet httpget = new HttpGet("http://localhost/";);  

CloseableHttpResponse response = httpclient.execute(httpget);  

try {  

     HttpEntity entity = response.getEntity();  

     if (entity != null) {  

        InputStream instream = entity.getContent();  

        try {  

            // do something useful  

        } finally {  

            instream.close();  

        }  

   }  

} finally {  

     response.close();  

}

 

关闭内容流和关闭响应的不一样点是:前者将会经过消费实体内容保持潜在的链接,然后者迅速的关闭并丢弃链接。

请注意,一旦实体被HttpEntity#writeTo(OutputStream)方法成功地写入时,也须要确保正确地释放系统资源。若是方法得到经过HttpEntity#getContent(),它也须要在一个finally子句中关闭流。

当使用实体时,你可使用EntityUtils#consume(HttpEntity)方法来确保实体内容彻底被消费而且使潜在的流关闭。

某些状况,整个响应内容的仅仅一小部分须要被取出,会使消费其余剩余内容的性能代价和链接可重用性代价过高,这时能够经过关闭响应来终止内容流。

CloseableHttpClient httpclient = HttpClients.createDefault();  

HttpGet httpget = new HttpGet("http://localhost/";);  

CloseableHttpResponse response = httpclient.execute(httpget);  

try {  

HttpEntity entity = response.getEntity();  

if (entity != null) {  

        InputStream instream = entity.getContent();  

    int byteOne = instream.read();  

        int byteTwo = instream.read();  

    // Do not need the rest  

}  

} finally {  

    response.close();  

}

这样,链接将不会被重用,它分配的全部级别的资源将会被解除。

 

消费实体内容

为了消费实体内容,推荐的方式是使用HttpEntity#getContent()或者 HttpEntity#writeTo(OutputStream)方法。HttpClient也提供了一个EntityUtils类,它有几个静态方法更容易的从实体中读取内容或信息。取代了直接读取java.io.InputStream,你能够经过这个类的方法取出所有内容体并放入一个String 中或者byte数组中。但是,强烈不建议使用EntityUtils,除非响应实体来自于信任的HTTP服务器而且知道它的长度。

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类包装起来。这将会使原始实体的内容读入一个in-memory缓冲区。全部方式的实体包装都是表明最原始的那个实体。

CloseableHttpResponse response = <...>  

HttpEntity entity = response.getEntity();  

if (entity != null) {  

    entity = new BufferedHttpEntity(entity);  

}

 

生产实体内容

HttpClient提供了几个类,用来经过HTTP链接高效地传输内容。

这些类的实例均与内含实体请求有关,好比POST和PUT,它们可以把实体内容封装进友好的HTTP请求中。

对于基本的数据容器String, byte array, input stream, and file,

HttpClient为它们提供了几个对应的类:StringEntity, ByteArrayEntity, InputStreamEntity, and FileEntity。

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);

请注意InputStreamEntity是不可重复的,由于它仅仅可以从数据流中读取一次。

通常建议实现一个定制的HttpEntity类来代替使用通常的InputStreamEntity。

FileEntity将会是一个好的出发点。

 

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);

UrlEncodedFormEntity实例像上面同样使用URL编码方式来编码参数并生成下面的内容:

param1=value1&param2=value2

 

内容分块

一般,咱们推荐让HttpClient选择基于被传递的HTTP报文属相最合适的传输编码方式。可能地,能够经过设置HttpEntity#setChunked()为true来通知HttpClient你要进行分块编码。注意HttpClient将会使用这个标志做为提示。当使用一些不支持分块编码的HTTP版本(好比HTTP/1.0.)时,这个值将会忽略。

【译者:分块编码是是HTTP1.1协议中定义的Web用户向服务器提交数据的一种方法】

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接口,它包含了一个handleResponse(HttpResponse response)方法。这个方法减轻使用者对于链接管理的担忧。

当你使用ResponseHandler时,不管是请求执行成功亦或出现异常,HttpClient将会自动地确保链接释放回链接管理器中。

CloseableHttpClient httpclient = HttpClients.createDefault(); 

HttpGet httpget = new HttpGet("http://localhost/json";); 

ResponseHandler<MyJsonObject> rh = new ResponseHandler<MyJsonObject>() 

@Override 

public JsonObject handleResponse(final HttpResponse response) throws IOException

 { 

StatusLine statusLine = response.getStatusLine(); 

HttpEntity entity = response.getEntity();

 if (statusLine.getStatusCode() >= 300) 

throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase()); 

}

 if (entity == null) 

{

 throw new ClientProtocolException("Response contains no content"); 

Gson gson = new GsonBuilder().create(); 

ContentType contentType = ContentType.getOrDefault(entity); 

Charset charset = contentType.getCharset(); 

Reader reader = new InputStreamReader(entity.getContent(), charset); 

return gson.fromJson(reader, MyJsonObject.class); 

}

 }; 

MyJsonObject myjson = client.execute(httpget, rh);

相关文章
相关标签/搜索