Java4Android之httpclient学习与应用

在Java开发中,不可避免的需要和http打交道。而无论我司的迅雷动漫还是我主导的“搜芽”android客户端开发,都需要使用到http和服务器打交道。。虽然Java也提供了http的接口,但据我了解,更多的公司都是使用Apache的httpclient来进行开发,不仅因为它灵活强大,而且便捷。

今天,我们学习httpclient的基础知识。

关于Http的基础,在此就不再复习了。建议大家去看一本权威制作《HTTP权威指南》,加个略贵,109元人民币,不过,我买了,因为经典的书,还是多备一下,我也没怎么看,但遇到问题就翻即可。

闲话少说,切入正题。

我们发出一个http的请求,在httpclient中一般如下流程模式:

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

代码示例如下:

CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpget = new HttpGet("http://localhost/");
CloseableHttpResponse response = httpclient.execute(httpget);
try {
<...>
} finally {
response.close();
}

请求:

HttpClient支持所有的HTTP/1.1的所有命令,包含:GET,HEAD,POST,PUT,DELETE,TRACE和OPTIONS。而且都有单独对应的类:HttpGet,HttpHead,....等等。

请求URI是统一资源标识符,标识了你所要请求的资源。它一般包含protocol scheme , host name, optional port, resource path,optional query ,optional fragment这些信息。如:

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

构造上述URI一个更为好的方法是使用URIBuilder。具体如下:

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

回复:

回复(response)是服务器对客户端的回复。httpclient中的回复是HttpResponse.

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.1
200
OK
HTTP/1.1 200 OK

消息头部:

如果大家熟悉HTTP包的话,就知道一个HTTP报文是由三个部分组成的:对报文进行描述的起始行(start line),包含属性的首部块(header),以及可选的,包含数据的主体部分(body)。

httpclient的一个关于头部的示例:

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=localhost
Set-Cookie: c2=b; path="/", c3=c; domain="localhost"
2

HTTP 实体(entity):

在httpclient中存在三种实体,streamed,self-contained和wrapping。它们的区别在我们用到的时候再区分,一般而言,流对象适合接收流数据,self-contained自包含适合那些可重复读取的场景。wrapping是对已有实体的一个包装。

下面是一个使用实体的例子:

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

对实体的使用:

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也提供了几个产生实体的类,分别产生对应的实体。StringEntity,ByteArrayEntity,InputStreamEntity和FileEntity,它们分别产生string, byte array, input stream ,file。一个fileEntity的示例如下:

File file = new File("somefile.txt");
FileEntity entity = new FileEntity(file,
ContentType.create("text/plain", "UTF-8"));
HttpPost httppost = new HttpP

表单:

httpclient也提供了类似与http表单的功能,比如用户登入页面,需要用户名和密码。

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

会产生如下效果:

param1=value1&m2=value2

在最后,我给出我们对httpclient的GET和POST 的方法的一个封装,这里里面的代码会将我们前面讲到的元素都涉及到。

 private InputStream httpGet(String url, String cookie) {
        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader("Accept-Encoding", "gzip,deflate");
        if (!(TextUtils.isEmpty(cookie))) {
            httpGet.setHeader("Cookie", cookie);
        }
        return httpDo(httpGet, url, null);
    }

    private InputStream httpPost(String url, Map<String, String> headers,
            Map<String, Object> params) {
        HttpPost post = new HttpPost(url);

        HttpEntity entity = null;
        Object value = params.get(POST_ENTITY);
        if (value instanceof HttpEntity) {
            entity = (HttpEntity) value;
        } else {
            List<NameValuePair> pairs = new ArrayList<NameValuePair>();
            for (Map.Entry<String, Object> e : params.entrySet()) {
                value = e.getValue();
                if (value != null) {
                    LOG.debug("param=" + e.getKey() + ":" + value.toString());
                    pairs.add(new BasicNameValuePair(e.getKey(), value
                            .toString()));
                }
            }
            try {
                entity = new UrlEncodedFormEntity(pairs, "UTF-8");
            } catch (UnsupportedEncodingException e1) {
                LOG.warn("UnsupportedEncodingException err={}", e1.toString());
            }
        }

        if (headers != null && !headers.containsKey("Content-Type")) {
            headers.put("Content-Type",
                    "application/x-www-form-urlencoded;charset=UTF-8");
        }
        post.setEntity(entity);

        return httpDo(post, url, headers);
    }

    private InputStream httpDo(HttpUriRequest hr, String url,
            Map<String, String> headers) {
        InputStream in = null;
        if (headers != null) {
            for (String name : headers.keySet()) {
                hr.addHeader(name, headers.get(name));
            }
        }

        DefaultHttpClient client = getClient();
        HttpResponse response;
        try {
            response = client.execute(hr);

            int statusCode = response.getStatusLine().getStatusCode();
            LOG.debug("this={}, response code={}", this, statusCode);

            if (statusCode == HttpStatus.SC_OK) {
                HttpEntity entity = response.getEntity();
                if (null != entity) {
                    Header header = entity.getContentEncoding();
                    if (header != null && header.getValue().equals("gzip")) {
                        in = new GZIPInputStream(entity.getContent());
                    } else {
                        in = entity.getContent();
                    }
                }
            } else {
                LOG.warn("Request HTTP resource failed. StatusCode={} Url={}", statusCode, url);
            }
        } catch (IOException e) {
            LOG.warn("Request HTTP resource failed. {}, err={}", this, e.toString());
        } catch (IllegalStateException e) {
            LOG.warn("Request HTTP resource failed. url={} err={}", url, e.toString());
        }

        return in;
    }

    private static DefaultHttpClient getClient() {
        HttpParams httpParams = new BasicHttpParams();
        HttpConnectionParams.setConnectionTimeout(httpParams, CONNECTION_TIMEOUT);
        HttpConnectionParams.setSoTimeout(httpParams, SO_TIMEOUT);
        // http://stackoverflow.com/questions/5358014/android-httpclient-oom-on-4g-lte-htc-thunderbolt
        HttpConnectionParams.setSocketBufferSize(httpParams, 8192);

        return new DefaultHttpClient(httpParams);
    }

时间有限,今天到此为止。

时间: 2024-11-18 00:57:15

Java4Android之httpclient学习与应用的相关文章

Java4Android之HttpClient入门使用代码集

本文将从代码的角度去引导如何使用httpclient的各个功能和特性. 第一个程序 import org.apache.commons.httpclient.*; import org.apache.commons.httpclient.methods.*; import org.apache.commons.httpclient.params.HttpMethodParams; import java.io.*; public class HttpClientTutorial { privat

ASP.NET MVC Web API 学习笔记----HttpClient简介

  1. HttpClient简单介绍  依稀还记得那个时候用WebClient,HttpWebRequest来发送一个请求,现在ASP.NET MVC4中自带了一个类HttpClient,用于接收HttpResponseMessage和发送HttpRequestMesssage. 问题在于既然WebClient,HttpWebRequest可以完成相应的功能,为什么还要使用HttpClient类,.NET Framework中既然提出了这样一个类肯定是有其特别之处的,这里罗列几个不同之处: (

Java4android学习之对象导论

今天开始的这个礼拜,回补java基本知识,再次回炉学习. 1 , 程序员必须建立起在机器模型和设计待解问题的模型之间的关联.建立这种关联是费力的,而且不属于编程语言所固有的功能,使得编程难以编写,并且维护代价高昂,同时也产生了作为副产物的整个"编程方法"行业. 2,对象具有状态,行为和标识.状态:每个对象可以拥有内部数据(它给出了对象的状态):方法:它们产生的行为:并且每个对象都可以和其他对象区分开来,具体就是每个对象在内存中都存在唯一的地址. 3,每个对象都有一个接口.创建抽象数据类

Cookies,SSL,httpclient的多线程处理,HTTP方法

client|cookie|cookies|多线程 - 作者 sunggsun @ 20:26 8.Cookies HttpClient能自动管理cookie,包括允许服务器设置cookie并在需要的时候自动将cookie返回服务器,它也支持手工设置cookie后发送到服务器端.不幸的是,对如何处理cookie,有几个规范互相冲突:Netscape Cookie 草案, RFC2109, RFC2965,而且还有很大数量的软件商的cookie实现不遵循任何规范. 为了处理这种状况,HttpCli

Android平台HttpClient的使用-手机号码归属地查询

Android平台主要提供了四种数据存储方式:Shared Preferences.文件存储.Sqlite存储和网络存储.其 中: 1)Shared Preferences 一个轻量级的键-值存储机制,专门用于存储键-值对数据,并且仅可以存储基本 的数据类型(boolean.int.long.float和String):通常使用它来存储应用程序的配置信息. 2)文件存储 通过FileInputStream和FileOutputStream对文件进行操作,在Android中,文件是一个应用 程序私

Android学习路上会遇到的各种瓶颈总结

本文讲的是Android学习路上会遇到的各种瓶颈总结,对于大多数大三学生来说,这个暑假是人生最后一个暑假.对于IT专业的学生来说,开学后就要面对各大IT企业的秋招,很多人会成为从0开始的Android实习生.在Android初学之路上,每个Android实习生都会遇到各式各样的瓶颈. 克服瓶颈要从克服自己对一切瓶颈的偏见做起,把逃避瓶颈的行为变成享受瓶颈带来的乐趣的过程.要知道喜力比国产啤酒贵好多的一条重要原因就在于喜力的瓶颈:你现在去买一瓶玻璃瓶装喜力,用手握住瓶颈,大拇指按住那颗星,然后用你

学习通过Thread+Handler实现非UI线程更新UI组件(转)

  [Android线程机制]    出于性能考虑,Android的UI操作并不是线程安全的,这就意味着如果有多个线程并发操作UI组件,可能导致线程安全问题.为了解决这个问题,Android制定了一条简单的规则:只允许UI线程修改Activity里的UI组件    当一个程序第一次启动时,Android会同时启动一条主线程(Main Thread),主线程主要负责处理与UI相关的事件,如用户的按键事件,用户接触屏幕的事件及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理.所以主线程通常又被叫

Android系列之网络(一)----使用HttpClient发送HTTP请求(通过get方法获取数据)

[正文]  一.HTTP协议初探: HTTP(Hypertext Transfer Protocol)中文 "超文本传输协议",是一种为分布式,合作式,多媒体信息系统服务,面向应用层的协议,是Internet上目前使用最广泛的应用层协议,它基于传输层的TCP协议进行通信,HTTP协议是通用的.无状态的协议. 这几个名词有一种通俗的解释: 通讯协议:双方对话的标准 通用的:用了都说好,谁用谁知道 无状态的:翻脸不认人 超文本:除了文本,还可以是音频.视频 HTTP协议与Android开发

Java4Android之APP自动升级

一个成熟的商业APP必须不断的退出新的版本.那么,不可能让用户自己去应用市场去下载新版本的应用,我们应该在应用内部提供自动升级的功能.自动升级其实包含两个层面,一个是整个APP的升级,也就是下载新版本的APP,然后安装替换掉现有的.还有一种升级是模块升级,这种升级一般采用静默升级,就是用户完全不知道.这个在我大迅雷里面经常做的,拿各个渠道去试错,对于一个互联网公司而言是再普通不过的了.而这些模块,肯定是诸如,解析库,下载库,播放库,这些后台库.. 不过今天,我要说的是APP的自动升级,模块的静默