目录:
HTTPClient根据其内容出自何处区分三种类型的实体
重复实体
使用HTTP实体
确保低级别资源释放
消耗实体内容
生成实体内容
动态内容实体
HTML表单
内容分块
HTTP报文可以携带和请求或响应相关的内容实体。实体可以在一些请求和响应中找到,因为它们也是可选的。使用了实体的请求被称为封闭实体请求。HTTP规范定义了两种封闭实体的方法:POST和PUT。响应通常期望包含一个内容实体。这个规则也有特例,比如HEAD方法的响应和204 NoContent,304 Not Modified和205 Reset Content响应。
HttpClient根据其内容出自何处区分三种类型的实体:
streamed流式
内容从流中获得,或者在运行中产生。特别是这种分类包含从HTTP响应中获取的实体。流式实体是不可重复生成的。
self-contained自我包含式
内容在内存中或通过独立的连接或其它实体中获得。自我包含式的实体是可以重复生成的。这种类型的实体会经常用于封闭HTTP请求的实体。
wrapping包装式
内容从另外一个实体中获得。
当从一个HTTP响应中获取流式内容时,这个区别对于连接管理很重要。对于由应用程序创建而且只使用HttpClient发送的请求实体,流式和自我包含式的不同就不那么重要了。这种情况下,建议考虑如流式这种不能重复的实体,和可以重复的自我包含式实体。
重复实体
实体可以重复,意味着它的内容可以被多次读取。这就仅仅是自我包含式的实体了(像ByteArrayEntity或StringEntity)。
使用HTTP实体
一个实体既可以代表二进制内容又可以代表字符内容,同时也支持字符编码。实体是在使用封闭内容执行请求,或当请求已经成功执行,或当响应体结果发送到客户端时创建的。
要从实体中读取内容,可以通过HttpEntity#getContent()方法从输入流中获取,这会返回一个java.io.InputStream对象,或者提供一个输出流到HttpEntity#writeTo(OutputStream)方法中,这会一次返回所有写入到给定流中的内容。
当实体通过一个收到的报文获取时,HttpEntity#getContentType()方法和 HttpEntity#getContentLength()方法可以用来读取通用的元数据,如Content-Type和Content-Length头部信息(如果它们是可用的)。因为头部信息Content-Type可以包含对文本MIME类型的字符编码,比如text/plain或text /html,HttpEntity#getContentEncoding()方法用来读取这个信息。如果头部信息不可用,那么就返回长度-1,而对于内容类型返回NULL。如果头部信息Content-Type是可用的,那么就会返回一个Header对象。
StringEntity entity =new StringEntity("important message","UTF-8");
System.out.println(entity.getContentType());
System.out.println(entity.getContentLength());
System.out.println(ContentType.getOrDefault(entity));
System.out.println(EntityUtils.toString(entity));
System.out.println(EntityUtils.toByteArray(entity).length);
输出:Content-Type: text/plain; charset=UTF-8
17
text/plain; charset=UTF-8
important message
17
确保低级别资源释放
当完成一个响应实体,那么保证所有实体内容已经被完全消耗是很重要的,所以连接可以安全的放回到连接池中,而且可以通过连接管理器对后续的请求重用连接。处理这个操作的最方便的方法是调用HttpEntity#consumeContent()方法来消耗流中的任意可用内容。HttpClient探测到内容流尾部已经到达后,会立即会自动释放低层连接,并放回到连接管理器。HttpEntity#consumeContent()方法调用多次也是安全的。
也可能会有特殊情况,当整个响应内容的一小部分需要获取,消耗剩余内容而损失性能,还有重用连接的代价太高,则可以仅仅通过调用HttpUriRequest#abort()方法来中止请求。
HttpGet httpGet =new HttpGet("http://www.baidu.com");
HttpResponse response = client.execute(httpGet);
HttpEntity entity = response.getEntity();
if (entity !=null) {
InputStream instream = entity.getContent();
int byteOne = instream.read();
int byteTwo = instream.read();
// Do not need the rest
httpGet.abort();
}
连接不会被重用,但是由它持有的所有级别的资源将会被正确释放。
消耗实体内容
推荐消耗实体内容的方式是使用它的HttpEntity#getContent()或HttpEntity#writeTo(OutputStream)方法。HttpClient也自带EntityUtils类,这会暴露出一些静态方法,这些方法可以更加容易地从实体中读取内容或信息。代替直接读取 java.io.InputStream,也可以使用这个类中的方法以字符串/字节数组的形式获取整个内容体。然而,EntityUtils的使用是强烈不鼓励的,除非响应实体源自可靠的HTTP服务器和已知的长度限制。
HttpGet httpGet =new HttpGet("http://localhost/");
HttpResponse response = client.execute(httpGet);
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
}
}
在一些情况下可能会不止一次的读取实体。此时实体内容必须以某种方式在内存或磁盘上被缓冲起来。最简单的方法是通过使用BufferedHttpEntity类来包装源实体完成。这会引起源实体内容被读取到内存的缓冲区中。在其它所有方式中,实体包装器将会得到源实体。
HttpGet httpGet =new HttpGet("http://localhost/");
HttpResponse response = client.execute(httpGet);
HttpEntity entity = response.getEntity();
if (entity !=null) {
entity = new BufferedHttpEntity(entity);
}
生成实体内容
HttpClient提供一些类,它们可以用于生成通过HTTP连接获得内容的有效输出流。为了封闭实体从HTTP请求中获得的输出内容,那些类的实例可以和封闭如POST和PUT请求的实体相关联。HttpClient为很多公用的数据容器,比如字符串,字节数组,输入流和文件提供了一些类:StringEntity,ByteArrayEntity,InputStreamEntity和FileEntity。
File file =new File("somefile.txt");
ContentType contentType = ContentType.create("text/plain","UTF-8");
FileEntity entity =new FileEntity(file, contentType);
HttpPost httpPost =new HttpPost("http://localhost/action.do");
httpPost.setEntity(entity);
请注意InputStreamEntity是不可重复的,因为它仅仅能从低层数据流中读取一次内容。通常来说,我们推荐实现一个定制的HttpEntity类,这是自我包含式的,用来代替使用通用的InputStreamEntity。FileEntity也是一个很好的起点。
动态内容实体
通常来说,HTTP实体需要基于特定的执行上下文来动态地生成。通过使用EntityTemplate实体类和ContentProducer接口,HttpClient提供了动态实体的支持。内容生成器是按照需求生成它们内容的对象,将它们写入到一个输出流中。它们是每次被请求时来生成内容。所以用EntityTemplate创建的实体通常是自我包含而且可以重复的。
ContentProducer cp =new ContentProducer() {
public void writeTo(OutputStream outstream) throws IOException {
Writer writer = new OutputStreamWriter(outstream,"UTF-8");
writer.write("");
writer.write(" ");
writer.write(" important stuff");
writer.write(" ");
writer.write("");
writer.flush();
}
};
HttpEntity entity =new EntityTemplate(cp);
HttpPost httppost =new HttpPost("http://localhost/handler.do");
httppost.setEntity(entity);
HTML表单
许多应用程序需要频繁模拟提交一个HTML表单的过程,比如,为了来记录一个Web应用程序或提交输出数据。HttpClient提供了特殊的实体类UrlEncodedFormEntity来这个满足过程。
List fromParams =new ArrayList();
fromParams.add(new BasicNameValuePair("param1","value1"));
fromParams.add(new BasicNameValuePair("param2","中文参数值"));
UrlEncodedFormEntity entity =new UrlEncodedFormEntity(fromParams,"UTF-8");
HttpPost httpPost =new HttpPost("http://localhost/handler.do");
httpPost.setEntity(entity);
UrlEncodedFormEntity实例将会使用URL编码来编码参数,生成如下的内容:
param1=value1¶m2=%E4%B8%AD%E6%96%87%E5%8F%82%E6%95%B0%E5%80%BC
内容分块
通常,我们推荐让HttpClient选择基于被传递的HTTP报文属性的最适合的编码转换。这是可能的,但是,设置HttpEntity#setChunked()方法为true是通知HttpClient分块编码的首选。请注意HttpClient将会使用标识作为提示。当使用的HTTP协议版本,如HTTP/1.0版本,不支持分块编码时,这个值会被忽略。
StringEntity entity =new StringEntity("important message",
"text/plain; charset=\"UTF-8\"");
entity.setChunked(true);
HttpPost httppost =new HttpPost("http://localhost/acrtion.do");
httppost.setEntity(entity);
原文地址:http://blog.csdn.net/tuxq5721/article/details/16891561