HttpClient 该知道不该知道的一些事


一、简介:

  • Apache开源项目: http://hc.apache.org/
  • 基于HTTP协议提供强大的支持,构建HTTP客户端应用程序
  • 执行HTTP协议时,包含了HTTP请求和响应不同状态,可以对关键参数设置和获取

二、HTTP协议(扫盲)

  • HTTP请求包含三部分,分别由请求行(请求方法)、请求头(消息报文)、请求正文组成。
  • HTTP请求详解:
     
  • HTTP 响应详解
    

三、URI URL和URN区别:

  • URI(Uniform Resource Identifier) 统一资源标识符
  • URL(Uniform Resource Locator)  统一资源定位符
  • URN(Uniform Resource Name)    统一资源名称
  • 整体关系:
          
 
  • 举个栗子么:
比如有一个虚拟地址,首先这是一个URI:
http://bitpoetry.io/posts/hello.html#intro
xxxxxxxxxx
1
 
1
http://bitpoetry.io/posts/hello.html#intro
我们分析:
http://
xxxxxxxxxx
1
 
1
http://
 是定义如何访问资源的方式。
bitpoetry.io/posts/hello.html
xxxxxxxxxx
1
 
1
bitpoetry.io/posts/hello.html
是资源存放的位置,那么,在这个栗子中,
#intro
xxxxxxxxxx
1
 
1
#intro
是资源。
  • URL是URI的一个子集,告诉我们访问网络位置的方式,
http://bitpoetry.io/posts/hello.html
xxxxxxxxxx
1
 
1
http://bitpoetry.io/posts/hello.html
  • URN是URI的子集,包括名字(给定的命名空间内),但不包括访问方式
bitpoetry.io/posts/hello.html#intro
xxxxxxxxxx
1
 
1
bitpoetry.io/posts/hello.html#intro

四、调用步骤:

  1. 创建 HttpClient 对象
  2. 创建请求方法的实例,并指定URL。
    1. GET 请求,创建 HttpGet 对象
    2. POST 请求,创建 HttpPost 对象
  3. 调用 SetParams(HttpParams params) 方法来添加请求参数,  对于 HttpPost 对象而言,也可以调用 setEntity(HttpEntity entity) 方法来设置请求参数
  4. 调用 HttpClient 对象的 execute(HttpUriRequest request) 发送请求,该方法返回一个 HttpResponse
  5. 调用 HttpResponse 的 getAllHeaders()、getHeaders(String name) 等方法可获取服务器的响应头;调用 HttpResponse 的 getEntity() 方法可获取 HttpEntity 对象,该对象包装了服务器的相应内容。程序可以通过获取服务器的相应内容
  6. 释放连接,无论执行方法是否成功,都必须释放连接
例如下图:
        

五、调用细节:

  • HttpClient提供了URIBuilder类来简化和修改请求URI
http://image.baidu.com/search/detail?ct=503316480&word=scheme
xxxxxxxxxx
1
 
1
http://image.baidu.com/search/detail?ct=503316480&word=scheme
     可以有如下写法:
URI uri = new URIBuilder()
.setScheme("http") //设置scheme
.setHost("image.baidu.com")//set host
.setPath("/search/detail")// set path
.setParameter("ct","503316480")// set param
.setParameter("word","scheme")
.build();
xxxxxxxxxx
7
 
1
URI uri = new URIBuilder()
2
                .setScheme("http") //设置scheme
3
                .setHost("image.baidu.com")//set host
4
                .setPath("/search/detail")// set path
5
                .setParameter("ct","503316480")// set param
6
                .setParameter("word","scheme")
7
                .build();

  • 在Response中几个关键参数获取:
response.getProtocolVersion() // 协议
response.getStatusLine().getStatusCode() //状态码
response.getStatusLine().getReasonPhrase()//表单含义
xxxxxxxxxx
3
 
1
response.getProtocolVersion() // 协议
2
response.getStatusLine().getStatusCode() //状态码
3
response.getStatusLine().getReasonPhrase()//表单含义
  • 获取给定类型的所有头部信息最有效的方式是使用HeaderIterator接口:
public static void main(String[] args) {
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 = a

path=/

domain=localhost

c2 = b

path=/

c3 = c

domain=localhost

xxxxxxxxxx
30
 
1
public static void main(String[] args) {
2
        HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
3
            response.addHeader("Set-Cookie", "c1=a; path=/; domain=localhost");
4
            response.addHeader("Set-Cookie", "c2=b; path=\"/\", c3=c; domain=\"localhost\"");
5
            HeaderElementIterator it = new BasicHeaderElementIterator(response.headerIterator("Set-Cookie"));
6
            while (it.hasNext()) {
7
                HeaderElement elem = it.nextElement(); 
8
                System.out.println(elem.getName() + " = " + elem.getValue());
9
                NameValuePair[] params = elem.getParameters();
10
                for (int i = 0; i < params.length; i++) {
11
                    System.out.println(" " + params[i]);
12
                }
13
          }
14
}
15

16
运行输出:
17

18
c1 = a
19

20
 path=/
21

22
 domain=localhost
23

24
c2 = b
25

26
 path=/
27

28
c3 = c
29

30
 domain=localhost

  • 为了保证系统资源被正确地释放,我们要么管理HTTP实体流,要么关闭http响应。
  • 关闭HTTP实体内容流和关闭HTTP响应的区别,前者通过消耗掉HTTP实体内容来保持相关HTTP连接,然而后者会立即关闭,丢弃HTTP连接。
  • HttpClient 推荐使用 HttpEntity 的 getContent() 方法或者 HttpEntity 的 writeTo(OutputStream) 方法读取Http实体内容。
  • EntityUtils 提供的方法可以以字符串或者字节数组的形式读取 Http 实体,但是一般不建议,确保相应的实体长度不大。
  • 希望把 Http 实体内容缓存在内存或者磁盘上,最简单方法就是把 Http Entity 转化为 BufferedHttpEntity,
CloseableHttpResponse response = <...>
HttpEntity entity = response.getEntity();
if (entity != null) {
entity = new BufferedHttpEntity(entity);
}
xxxxxxxxxx
5
 
1
CloseableHttpResponse response = <...>
2
HttpEntity entity = response.getEntity();
3
if (entity != null) {
4
    entity = new BufferedHttpEntity(entity);
5
}
  • HttpClient 提供了一些类,这些类可以通过http连接高效地输出Http实体内容。
  • HttpClient 提供的这几个类涵盖的常见的数据类型,如String,byte 数组,输入流,和文件类型:StringEntity,ByteArrayEntity,InputStreamEntity,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);

xxxxxxxxxx
6
 
1
File file = new File("somefile.txt");
2
FileEntity entity = new FileEntity(file, 
3
    ContentType.create("text/plain", "UTF-8"));        
4
 
5
HttpPost httppost = new HttpPost("http://localhost/action.do");
6
httppost.setEntity(entity);
  • 请注意由于 InputStreamEntity 只能从下层的数据流中读取一次,所以它是不能重复的。推荐,通过继承 HttpEntity 这个自包含的类来自定义HttpEntity 类,而不是直接使用 InputStreamEntity 这个类。FileEntity 就是一个很好的起点(FileEntity 就是继承的 HttpEntity)。
  • 模拟 HTML 表单提交
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);
xxxxxxxxxx
6
 
1
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
2
formparams.add(new BasicNameValuePair("param1", "value1"));
3
formparams.add(new BasicNameValuePair("param2", "value2"));
4
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams, Consts.UTF_8);
5
HttpPost httppost = new HttpPost("http://localhost/handler.do");
6
httppost.setEntity(entity);

  • 设置传输编码方式(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);
xxxxxxxxxx
 
1
StringEntity entity = new StringEntity("important message",
2
        ContentType.create("plain/text", Consts.UTF_8));
3
entity.setChunked(true);
4
HttpPost httppost = new HttpPost("http://localhost/acrtion.do");
5
httppost.setEntity(entity);

  • 处理http响应的方法就是使用ResponseHandler接口,这个接口中有handleResponse(HttpResponse response)方法。使用这个方法,用户完全不用关心http连接管理器。当使用ResponseHandler时,HttpClient会自动地将Http连接释放给Http管理器,即使http请求失败了或者抛出了异常。
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);

xxxxxxxxxx
26
 
1
CloseableHttpClient httpclient = HttpClients.createDefault();
2
HttpGet httpget = new HttpGet("http://localhost/json");
3
 
4
ResponseHandler<MyJsonObject> rh = new ResponseHandler<MyJsonObject>() {
5
 
6
    @Override
7
    public JsonObject handleResponse(
8
            final HttpResponse response) throws IOException {
9
        StatusLine statusLine = response.getStatusLine();
10
        HttpEntity entity = response.getEntity();
11
        if (statusLine.getStatusCode() >= 300) {
12
            throw new HttpResponseException(
13
                    statusLine.getStatusCode(),
14
                    statusLine.getReasonPhrase());
15
        }
16
        if (entity == null) {
17
            throw new ClientProtocolException("Response contains no content");
18
        }
19
        Gson gson = new GsonBuilder().create();
20
        ContentType contentType = ContentType.getOrDefault(entity);
21
        Charset charset = contentType.getCharset();
22
        Reader reader = new InputStreamReader(entity.getContent(), charset);
23
        return gson.fromJson(reader, MyJsonObject.class);
24
    }
25
};
26
MyJsonObject myjson = client.execute(httpget, rh);
































 

最新文章

  1. sublime如何自动保存
  2. 【Android自学日记】搭建Android开发环境
  3. HTML5 &lt;a&gt;标签的ping属性用法
  4. Java 监控请求
  5. android Camera 中添加一种场景模式
  6. http://www.cnblogs.com/dumuqiao/p/3654702.html?utm_source=tuicool&amp;utm_medium=referral
  7. [WinForm]TextBox只能输入数字或者正浮点型数字
  8. InstallShield集成安装MSDE2000最小版本(二) fishout特许授权发布
  9. flask入门
  10. android:layout_weight属性详解
  11. NeuChar 平台使用及开发教程(六):成为开发者
  12. ImportError: cannot import name &#39;Process&#39; from &#39;multiprocessing&#39;
  13. 自学华为IoT物联网_05 能源工业物联网常见问题及解决方案
  14. 剑指offer 02:替换空格
  15. thymeleaf 的标准表达式
  16. 01,WP8开发基础
  17. RequireJs 与 SeaJs的相同之处与区别
  18. 15-js提交表单的简单检测实例
  19. C++ 实现vector&lt;std:string&gt; 版本
  20. css Table布局:基于display:table的CSS布局

热门文章

  1. C开发系列-include
  2. 解决element-ui表头错位的问题
  3. [转]Visual Studio 2010生成解决方案时,提示磁盘空间不足!
  4. leetcode242 Valid Anagram
  5. 阿里云HBase Ganos全新升级,推空间、时空、遥感一体化基础云服务
  6. leyou_07_对数据的操作
  7. [转]模块化——Common规范及Node模块实现(二)
  8. 自己动手编写JEECMS自定义栏目统计标签
  9. PHP 缓存详解
  10. tensorflow使用CPU可以跑(运行),但是使用GPU却不能用的情况