HttpClient学习——0.简介

1.0 一个简单的Demo程序

下面是一个HttpClient通过Get方法访问www.baidu.com的请求Demo。我们将根据这个Demo介绍HttpClient的一些基本使用。

public class HttpClientDemo {

    CloseableHttpClient httpClient;

    @Before
    public void init() {
        httpClient = HttpClients.createDefault();
    }

    /**
     * httpClient执行get请求
     */
    @Test
    public void getMethodDemo() throws IOException {

        HttpGet httpget = new HttpGet("http://www.baidu.com/");
        CloseableHttpResponse response = httpClient.execute(httpget);
        try {
            // TODO
            HttpEntity entity = response.getEntity();       //http实体
            InputStream inputStream = entity.getContent();
            String str = IOUtils.toString(inputStream, "utf-8");
            System.out.println(str);
            EntityUtils.consume(entity);    //关闭了entity.getContent()的流 如果未关闭,则connection manager会关闭并丢弃这个连接
            System.out.println(response);

        } finally {
            response.close();               //关闭Http连接,execute方法中应该已经关闭
            httpClient.close();
        }
    }
}

1.1 Http请求

Http请求包含三部分:方法名称(Get,Post等),请求URI和HTTP协议版本。

HttpClient为每一个Http方法封装了一个类,例如常用的HttpGet,HttpPost。我们可以通过下面的方式来创建一个Http请求:

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

这样直接将请求固定在字符串中。事实上,一个Request-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);

1.2 HttpEntity

HTTP消息可以携带与请求或响应相关联的内容实体。HTTP规范定义了两个实体封装请求方法:POST和 PUT。响应通常期望包含内容实体。

1.2.1 创建HttpEntity

我们可以通过下面的方式创建一个HttpEntity。在HttpClient中有几种内容实体的类:StringEntity, ByteArrayEntity,InputStreamEntity和 FileEntity。

StringEntity myEntity = new StringEntity("important message",
   ContentType.create("text/plain", "UTF-8"));

使用较多的是Post提交表单的情况,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);

1.2.1 读取HttpEntity内容

要从实体读取内容,可以通过HttpEntity#getContent()方法来获取输入流,该方法返回一个java.io.InputStream。我们可以通过下面的方式读取HttpEntity的内容。

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

HttpClient提供了对HttpEntity操作的工具类EntityUtils。我们可以使用EntityUtils#toString()方法来将InputStream转换成一个String(apache.commons.io的IOUtils#toString()方法也可以实现相同的功能)

多次读取实体内容*

由于InputStream是不能够多次读取的,如果我们需要多次读取实体内容,可以使用BufferedHttpEntity类包装原始实体。

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

1.2.2 HttpEntity关闭

关闭内容流HttpEntity#getContent()和关闭response之间的区别是,前者将尝试通过占用实体内容来保持底层连接,而后者会立即关闭并丢弃连接。

当使用流实体时,可以使用该 EntityUtils#consume(HttpEntity)方法来确保实体内容已被完全消耗,底层流已经被关闭。如果不使用in.close(),而仅仅使用response.close(),结果就是连接会被关闭,并且不能被复用,这样就失去了采用连接池的意义。

1.3 处理HttpResponse

处理响应的最简单和最方便的方法是使用ResponseHandler包含该handleResponse(HttpResponse response)方法的接口。该方法完全可以缓解用户不必担心连接管理。使用ResponseHandlerHttpClient 时 ,无论请求执行是成功还是导致异常,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);

1.4 自定义HttpClient

之前我们都通过HttpClients#createDefault()方法来创建HttpClient,实际使用时我们希望订制适用于业务场景的HttpClient。例如连接时间的管理,见下面的例子:

ConnectionKeepAliveStrategy keepAliveStrat = new DefaultConnectionKeepAliveStrategy() {

    @Override
    public long getKeepAliveDuration(
            HttpResponse response,
            HttpContext context) {
        long keepAlive = super.getKeepAliveDuration(response, context);
        if (keepAlive == -1) {
            // Keep connections alive 5 seconds if a keep-alive value
            // has not be explicitly set by the server
            keepAlive = 5000;
        }
        return keepAlive;
    }

};
CloseableHttpClient httpclient = HttpClients.custom()           //自定义HttpClient
        .setKeepAliveStrategy(keepAliveStrat)
        .build();

HttpClient是线程安全的,建议将此类的同一个实例重用于多个请求执行,而不是发起一次请求就创建一个HttpClient。
当一个实例CloseableHttpClient不再需要时,与它关联的连接管理器必须通过调用该CloseableHttpClient#close() 方法来关闭。

1.5 HttpContext

最初HTTP被设计为无状态的,响应请求的协议。对于需要多次交互的请求,我们需要在连续请求之间重复使用相同的上下文,则多个逻辑相关请求可以参与逻辑会话。

在HTTP请求执行过程中,HttpClient将以下属性添加到执行上下文中:

  • HttpConnection 表示与目标服务器的实际连接的实例
  • HttpHost 表示连接目标的实例
  • HttpRoute 表示完整的连接路由的实例
  • HttpRequest表示实际HTTP请求的实例。执行上下文中的最终HttpRequest对象总是表示消息的状态与发送到目标服务器的状态完全相同。默认HTTP / 1.0和HTTP / 1.1使用相对请求URI
  • HttpResponse 表示实际的HTTP响应。
  • java.lang.Boolean 表示表示实际请求是否被完全发送到连接目标的标志的对象。
  • RequestConfig 表示实际请求配置的对象。
  • java.util.List 表示在请求执行过程中接收到的所有重定向位置的集合的对象。
    需要说明的是,HttpContext不是线程安全的。这一点很好理解。因此我们需要每个发起请求的线程维护自己的HttpContext。

参考:
httpclient官方文档

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值