# HTTP协议与HttpClient

所谓的协议都是“标准”,就像人们交流沟通时使用普通话一样,这是一种规范、一个标准,否则,人们的交流沟通就会出现阻塞、障碍,那么,网络之间的通讯也需要这样一种标准,这就是一种协议,HTTP协议是就是浏览器与服务器之间对话的这样一种标准。

HTTP协议是“超文本传输协议”(超文本传输的意思是:不局限于文本,还可以是音频、视频),可以用四个字总结其概要:“有求必应”,即:有请求必有应答。它处于应用层,是基于传输层的TCP协议进行通信,它是通用的(现在互联网用的最多的就是HTTP协议,例如访问网站,手机上的应用程序)、无状态(无状态的意思就是:当请求应答完成后,浏览器与服务器之间连结的状态就断开了,这样的优势就是可以节省网络资源,缺点是服务器无法主动去连结浏览器)的协议。

HTTP协议与Android之间的关系:用户使用某一个应用程序时,会向服务器去请求数据,那么手机上的应用程序就扮演了浏览器的角色。即:用户操作应用程序,然后由应用程序向服务器请求数据(应用程序开启一个新线程去请求数据),服务器作出响应将处理后的数据打包返回到应用程序,然后再由应用程序反馈给用户。

一个简单的纯粹的信息展示类的应用程序(例如:新闻客户端、微博等),无非就是四项技术加在一起:简单的UI,简单的线程,简单的网络以及简单的数据存储。

# 一.HttpClient的使用步骤

HttpClient是由Apache基金会开发的一套开源类库,属于HttpComponents的一部分,它是HTTP/1.1协议下的一种实现,由于它是开源的,Android也是开源的,所以Android就将这一类库整合到了Android里面,所以在Android应用程序中无需引用类库,直接使用就行。

TIP

1.生成代表客户端的HttpClient对象;

2.生成代表请求的HttpGet对象;

3.发送请求,获得服务器返回的HttpResponse对象;

4.检查响应状态是否正常;

5.获取响应对象当中的数据;

# 二.HTTP请求头与响应头

请求头与响应头其实就是一系列的文本数据,里面包含的内容统统都是键值对,每一个键值对都有一个含义。

请求头Request Headers详解(这是一个get方式的请求头):

WARNING

Host: baidu.com === Host就是本次请求访问主机地址

Cache-control:no-cache === Cache-control设置网页缓存的使用方法

Pragma:no-cache === PragmaCache-control一样,都是设置网页缓存的使用方法

Accept: text/html,xxxxxx…… === Accept:浏览器可以接受的数据类型,告诉服务器我可以接受的数据类型是什么

User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36 === User-Agent主要表示客户端类型,也就是说我现在正在使用什么样的客户端访问服务器

Accept-Encoding: gzip, deflate === Accept-Encoding表示浏览器能够解码的数据编码方式,也就是说服务器在向客户端响应发送数据时的数据的格式,例如传送一个较大的文件时可以先在服务器端进行压缩,然后再发送,而在客户端则必须能够解码这样的数据格式才能够得到这样的响应,然后解压缩出来,这样可以节省占用网络资源传输的时间,增加传输效率。

Accept-Language: zh-CN,zh;q=0.8 === Accept-Language表示浏览器期望接受的语言种类。

响应头Response Headers详解

TIP

Content-Encoding: gzip, deflate, sdch ===服务器端返回给客户端的数据的压缩格式

Content-Length: 0 ===服务器端返回数据量的大小(返回内容包含多少个字节的长度)

Content-Type ===服务器端返回数据的类型,例如音频、视频、文本

Last-Modifined ===客户端所访问的资源最后一次修改的时间

Date:Tue, 01 Mar 2016 13:27:23 GMT ===返回数据的时间

Server:nginx/1.8.0 ===服务器端的类型

三.综上,代码案例:

public class MainActivity extends Activity {

    private Button button;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        button = (Button) findViewById(R.id.clickButton);
        ButtonClickListenner buttonClickListenner = new ButtonClickListenner();
        button.setOnClickListener(buttonClickListenner);
    }

    class ButtonClickListenner implements OnClickListener{
        @Override
        public void onClick(View arg0) {
            // 在这里铭记一个原则:在主线程当中不能访问网络(这是在Android4.0以后加入的概念)
            WorkerThread workerThread = new WorkerThread();
            workerThread.start();
        }
    }
    
    class WorkerThread extends Thread{
        @Override
        public void run(){
            //第一步,创建HttpClient对象
            HttpClient httpClient = new DefaultHttpClient();
            //第二步,创建代表请求的对象,参数是访问的服务器的地址
            HttpGet httpget = new HttpGet("http://www.marschen.com/data1.html");
            //有了请求对象,在此就可以获取请求头的内容,但是目前是在代码中请求服务器的,因此需要自己去设置请求头
            //如果是在浏览器上请求访问的,那么这个请求头是浏览器放进去的
            //在做安全认证时,一般有两种认证数据的方式,一种是通过post将认证数据提交至服务器,还有一种就是将认证数据放在请求头中。
            httpget.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36");
            Header[] requestHeaders = httpget.getAllHeaders();
            for (Header header : requestHeaders) {
                String headerName = header.getName();
                String headerValue = header.getValue();
                Log.d("HTTP01", "requestHeaders----Name:"+headerName+",Value:"+headerValue);
            }
            //第三步,执行请求,获取发还的相应对象
            try {
                HttpResponse httpResponse = httpClient.execute(httpget);
                //在此可以获取响应头的内容
                Header[] responseHeaders = httpResponse.getAllHeaders();
                for (Header header : responseHeaders) {
                    String headerName = header.getName();
                    String headerValue = header.getValue();
                    Log.d("HTTP01", "responseHeaders----Name:"+headerName+",Value:"+headerValue);
                }
                //第四步,检查响应状态是否正常(检查状态码的值是否等于200)
                int statusCode = httpResponse.getStatusLine().getStatusCode();
                if(200 == statusCode){//正常
                    //第五步,从相应对象当中取出数据
                    HttpEntity entity = httpResponse.getEntity();
                    InputStream inStream = entity.getContent();
                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inStream));
                    String str = bufferedReader.readLine();
                    Log.d("HTTP", "从服务器取得的数据是:"+str);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

AndroidManifest.xml文件中加入代码:

<uses-permission android:name="android.permission.INTERNET"/>
1

这句代码就是为该程序申请了权限,就是在安装应用程序时系统会提示:提醒用户这个程序是要访问网络的,如果同意则执行安装,不同意则不安装该程序。一般情况下,用户根本不看这个提示。