本文共 10455 字,大约阅读时间需要 34 分钟。
更多HttpClient4.5中文教程请查看:
==================================
HttpClient最基本的功能是执行HTTP方法,一次 HTTP 方法的执行包含一个或多个 HTTP 请求/响应的交互,通常由 HttpClient的内部来处理。使用者需要提供一个Request对象来执行HTTP请求,HttpClient就会把请求传送给目标服务器并返回一个相对应的Response对象,如果执行不成功,将会抛出一个异常。
显然,HttpClient API 的主要切入点就是定义描述上述契约的HttpClient接口。一个简单的请求执行事例:
CloseableHttpClient httpclient = HttpClients.createDefault();HttpGet httpget = new HttpGet("http://localhost/");CloseableHttpResponse response = httpclient.execute(httpget);try { <...>} finally { response.close();}
所有 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工具类来简化创建、修改请求 URIs。
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);System.out.println(httpget.getURI());输出:
http://www.google.com/search?q=httpclient&btnG=Google+Search&aq=f&oq=
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.1200OKHTTP/1.1 200 OK
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);输出:
Set-Cookie: c1=a; path=/; domain=localhostSet-Cookie: c2=b; path="/", c3=c; domain="localhost"2
获得所有指定类型首部最有效的方式是使用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());}输出:
Set-Cookie: c1=a; path=/; domain=localhostSet-Cookie: c2=b; path="/", c3=c; domain="localhost"
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]); }}输出:
c1 = apath=/domain=localhostc2 = bpath=/c3 = cdomain=localhost
HTTP报文能够携带与请求或相应相关联的内容实体。实体存在于某些请求、响应中,它门是可选的。使用实体的请求被称为内含实体请求(entity enclosing requests)。HTTP规范定义了两种内含实体请求,POST和PUT。而响应总是内含实体(有些响应不符合这一规则,比如,对HEAD方法的响应和状态为204 No Content, 304 Not Modified, 205 Reset Content的响应)。
依据实体的内容来源,HttpClient区分出三种实体:流式实体(streamed):内容来源于一个流,或者在运行中产生【译者:原文为generated on the fly】。特别的,这个类别包括从响应中接收到的实体。流式实体不可重复。自包含实体(self-contained):在内存中的内容或者通过独立的连接/其他实体获得的内容。自包含实体是可重复的。这类实体大部分是HTTP内含实体请求。包装实体(wrapping):从另外一个实体中获取内容。
一个实体能够被重复,意味着它的内容能够被读取多次。它仅可能是自包含实体(像ByteArrayEntity或StringEntity)
由于一个实体能够表现为二进制和字符内容,它支持二进制编码(为了支持后者,即字符内容)。
实体将会在一些情况下被创建:当执行一个含有内容的请求时或者当请求成功,响应体作为结果返回给客户端时。为了读取实体的内容,可以通过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);输出:
Content-Type: text/plain; charset=utf-817important message17
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();}
这样,连接将不会被重用,它分配的所有级别的资源将会被解除。
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);}
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将会是一个好的出发点。
ListUrlEncodedFormEntity实例像上面一样使用URL编码方式来编码参数并生成下面的内容:formparams = new ArrayList ();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¶m2=value2
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);
CloseableHttpClient httpclient = HttpClients.createDefault();HttpGet httpget = new HttpGet("http://localhost/json");ResponseHandlerrh = new ResponseHandler () { @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);
转载地址:http://znhgi.baihongyu.com/