文档章节

Android 网络(一)

紫韵
 紫韵
发布于 2016/03/24 16:38
字数 2551
阅读 100
收藏 6

一、Http协议

1、HTTP简介

    大多数的Android应用程序都会使用HTTP协议来发送和接收网络数据,Android中主要提供了两种方式来进行HTTP操作,HttpURLConnection和HttpClient。所以首先介绍下Http协议。HTTP(HyperText Transfer Protocol,超文本传输协议) 是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。HTTP协议采用了请求/响应模型。通常,由HTTP客户端发起一个请求,建立一个到服务器指定端口(默认是80端口)的TCP连接,HTTP服务器则在那个端口监听客户端发送过来的请求。一旦收到请求,服务器(向客户端)发回一个状态行和响应消息,最后消息传送完毕时,可以关闭客户端和服务器端的连接。

2、HTTP消息

    Http消息由从客户机到服务器的请求和从服务器到客户机的响应构成。这两种类型的消息均由一个起始行,一个或者多个头域,一个指示头域结束的空行和可选的消息体组成。HTTP的头域包括通用头,请求头,响应头和实体头四个部分。

    请求消息格式如下:

    请求行 - 通用信息头 - 请求头 - 实体头 - 消息主体

     如下所示:

    

    应答消息格式如下:

    状态行 - 通用信息头 - 响应头 - 实体头 - 消息主体

     如下所示:

    

 3、请求方法

    注:Android HttpUrlConnection中只未提供Connect方法        

方法

 

GET

请求指定url的数据,请求体为空(例如打开网页)

POST

请求指定url的数据,同时传递参数(在请求体中)

HEAD

类似于get请求,只不过返回的响应体为空,用于获取响应头

PUT

从客户端向服务器传送的数据取代指定的文档的内容

DELETE

请求服务器删除指定的页面

CONNECT

HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器

OPTIONS

允许客户端查看服务器的性能

TRACE

回显服务器收到的请求,主要用于测试或诊断。

 4、状态码详解(Status Code)

    状态码是一个用于标识服务器响应结果的代码,由3位数字表示。状态码的第一个数字定义响应的类别,后两个数字没有分类的作用。(状态码后面会跟随一段用于简要描述状态码信息的文本)

    状态码类型:

类型

类型描述

1xx

信息响应类,表示接收到请求并且继续处理

2xx

处理成功响应类,表示动作被成功接收、理解和接受

3xx

重定向响应类,为了完成指定的动作,必须接受进一步处理

4xx

客户端错误,客户请求包含语法错误或者是不能正确执行

5xx

服务端错误,服务器不能正确执行一个正确的请求

    常见状态码详解:

状态码

描述

200 OK

请求成功(其后是对GET和POST请求的应答文档)

301 Moved Permanently

所请求的页面已经转移至新的url

304 Not Modified

服务器端的数据在If-modified-since后未发生修改

400 Bad Request

服务器未能理解请求

401 Unauthorized

被请求的页面需要用户名和密码

404 Not Found

服务器无法找到被请求的页面

408 Request Timeout

请求超出了服务器的等待时间

500 Internal Server Error

请求未完成。服务器遇到不可预知的情况

501 Not Implemented

请求未完成。服务器不支持所请求的功能

5、头域详解

  • 通用头域

    通用头域包含请求和响应消息都支持的头域,通用头域包含Cache-Control、Connection、Date、Pragma、Transfer-Encoding、Upgrade、Via.
    1) Cache-Control:Cache-Control指定请求和响应遵循的缓存机制。请求时的缓存指令包括no-cache、no-store、max-age、max-stale、min-fresh、only-if-cached,响应消息中的指令包括public、private、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、max-age。
    2) Date头域:Date头域表示消息发送的时间,如Date:Mon,31Dec200104:25:57GMT

  • 请求头域

    请求头域中包含请求消息特有的头域信息,如Host、Range、User-Agent等

    1) Host:Host头域指定请求资源的Intenet主机和端口号;

    2)Range:Range头域可以请求实体的一个或者多个子范围,如bytes=500-600,601-9993);

    3)User-Agent:User-Agent头域的内容包含发出请求的用户信息

  • 响应头域

    响应头域中包含响应消息中特有的头域信息,如Location、Server等

  • 1)Location:Location头域用于重定向接收者到一个新URI地址;

    2)Server:Server头域包含处理请求的原始服务器的软件信息;

  • 实体头域

    请求消息和响应消息都可以包含实体信息,实体信息一般由实体头域和实体组成。实体头域包含关于实体的原信息,实体头包括Allow、Content-Base、Content-Encoding、Content-Language、Content-Length、Content-Location、Content-MD5、Content-Range、Content-Type、Etag、Expires、Last-Modified、extension-header;

  • 1)Content-Type:Content-Type实体头用于向接收方指示实体的介质类型,指定HEAD方法送到接收方的实体介质类型,或GET方法发送的请求介质类型;

    2)Content-Range:Content-Range实体头用于指定整个实体中的一部分的插入位置,他也指示了整个实体的长度。主要用于对范围请求的响应或对一系列范围的重叠请求。
    一般格式:Content-Range:bytes-unitSPfirst-byte-pos-last-byte-pos/entity-legth
    如:Content-Range:bytes0-499/1234;

    3)Last-modified:Last-modified实体头指定服务器上保存内容的最后修订时间 

二、HttpClient & HttpURLConnection

1、HttpClient VS HttpURLConnection

    HttpClient和HttpURLConnection是Android中提供的两种进行HTTP操作的方式,这两种方式都支持HTTPS协议、以流的形式进行上传和下载、配置超时时间、IPv6、以及连接池等功能。

      DefaultHttpClient和AndroidHttpClient都是HttpClient的具体实现类,都拥有众多的API,而且实现比较稳定,bug数量也很少。但同时也由于HttpClient的API数量过多,使得很难在不破坏兼容性的情况下对它进行升级和扩展,所以目前Android团队在提升和优化HttpClient方面的工作态度并不积极;

    而HttpURLConnection是一种多用途、轻量极的HTTP客户端,使用它来进行HTTP操作可以适用于大多数的应用程序,同时其升级与维护也相对比较简单。但在Android 2.3版本之前,HttpURLConnection一直存在着一些令人厌烦的bug。比如说对一个可读的InputStream调用close()方法时,就有可能会导致连接池失效。通常的解决办法就是直接禁用掉连接池的功能。

     注意:Google建议Android2.3及以上版本的应用使用HttpURLConnection,而Android2.3以下版本的应用使用HttpClient。原因如下:

    在Android 2.2版本之前,HttpClient拥有较少的bug,因此使用它是最好的选择。
    而在Android 2.3版本及以后,HttpURLConnection则是最佳的选择。它的API简单,体积较小,因而非常适用于Android项目。压缩和缓存机制可以有效地减少网络访问的流量,在提升速度和省电方面也起到了较大的作用。同时,Google Android团队也在积极对该方式进行维护和升级。

2、HttpURLConnection的使用

/**
 * 采用HttpURLConnection进行网络请求的工具类
 */
public class AsyncNetworkUtil {
    private static String TAG = "AsyncNetworkUtil";

    /**
     * 发送一个post请求
     * @param url:请求的地址
     * @param content:post请求参数
     * @return: 返回服务器响应信息
     */
    public static String post(String url, String content) {
        HttpURLConnection conn = null;
        String response = null;
        try {
            // 创建一个URL对象
            URL mURL = new URL(url);
            // 调用URL的openConnection()方法,获取HttpURLConnection对象
            conn = (HttpURLConnection) mURL.openConnection();

            conn.setRequestMethod("POST");// 设置请求方法为post
            conn.setReadTimeout(5000);// 设置读取超时为5秒
            conn.setConnectTimeout(10000);// 设置连接网络超时为10秒
            conn.setUseCaches(false);   //设置不使用缓存
            conn.setDoOutput(true);// 设置此方法,允许向服务器输出内容

            // post请求的参数
            String data = content;
            // 获得一个输出流,向服务器写数据,默认情况下,系统不允许向服务器输出内容
            OutputStream out = conn.getOutputStream();
            out.write(data.getBytes());
            out.flush();
            out.close();

            int responseCode = conn.getResponseCode();// 调用此方法就不必再使用conn.connect()方法
            if (responseCode != -1) {
                InputStream is = conn.getInputStream();
                response = getStringFromInputStream(is);
            } else {
                response = "No valid response code";
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (conn != null) {
                conn.disconnect();// 关闭连接
            }
        }
        return response;
    }

    /**
     * 发送一个get请求
     * @param url:请求的地址
     * @return: 响应信息
     */
    public static String get(String url) {
        HttpURLConnection conn = null;
        try {
            // 利用string url构建URL对象
            URL mURL = new URL(url);
            conn = (HttpURLConnection) mURL.openConnection();

            conn.setRequestMethod("GET");
            conn.setReadTimeout(5000);
            conn.setConnectTimeout(10000);
            conn.connect();

            int responseCode = conn.getResponseCode();
            if (responseCode == 200) {
                InputStream is = conn.getInputStream();
                String response = getStringFromInputStream(is);
                return response;
            }else if ((responseCode + "") != null && (responseCode + "").length() != 0){
                return responseCode + " ";
            }
            else {
                throw new NetworkErrorException("response status is "+responseCode);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {

            if (conn != null) {
                conn.disconnect();
            }
        }
        return null;
    }

    /**
     * 从输入流中获取数据
     * @param is
     * @return
     * @throws IOException
     */
    private static String getStringFromInputStream(InputStream is)
            throws IOException {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        // 模板代码 必须熟练
        byte[] buffer = new byte[1024];
        int len = -1;
        while ((len = is.read(buffer)) != -1) {
            os.write(buffer, 0, len);
        }
        is.close();
        String state = os.toString();// 把流中的数据转换成字符串,采用的编码是utf-8(模拟器默认编码)
        os.close();
        return state;
    }

}

 

三、Android网络操作一般流程

  1. 开启网络权限

  2. <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  3. 检查设备的网络连接状况

  4.  /**
     * 这是一个工具类,用于检测网络连接状况
     */
    public class NetworkConnectivityUtil {
        private static String TAG = "NetworkConnectivityUtil";  //Log Tag
        private static ConnectivityManager connMgr; //网络连接管理器对象
        public NetworkConnectivityUtil(Context ctx){
            connMgr = (ConnectivityManager) ctx.getSystemService(ctx.CONNECTIVITY_SERVICE);
        }
        /**
         * 检查网络连接状况
         * @return  true:网络连通
         *          false:网络未连通
         */
        public boolean checkNetwork() {
            NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
            return networkInfo.isConnected() ? true : false;
        }
        /**
         * 检查WIFI连接状况
         * @return  true:网络连通
         *          false:网络未连通
         */
        public boolean checkWifi() {
            NetworkInfo wifiInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
            return wifiInfo.isConnected() ? true : false;
        }
        /**
         * 检查手机网络连接状况
         * @return  true:网络连通
         *          false:网络未连通
         */
        public boolean checkMobile() {
            NetworkInfo mobileInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
            return mobileInfo.isConnected() ? true : false;
        }
    }
  5. 在工作线程中进行网络操作

  6. /**
     * 通过一个异步任务AsyncTask进行网络操作
     */
     new AsyncTask<String, Void, String>() {
       @Override
       protected String doInBackground(String... params) {
          //NetworkUtil.get即上面HttpURLConnection中的方法
          return NetworkUtil.get(params[0]);
       }
       @Override
       protected void onPostExecute(String s) {
          editText.setText(s.substring(0, 100));
       }
    }.execute(url);

© 著作权归作者所有

共有 人打赏支持
紫韵
粉丝 3
博文 21
码字总数 34323
作品 0
武汉
加载中

评论(1)

h
heart162
可以参考下okhttp的框架对各种头部的具体处理,http协议定义了那么多,对应的很多东西还是需要自己去实现处理的
Android 9.0 Pie以下全中招的安卓新漏洞!可致设备被追踪

Nightwatch Cybersecurity于8月29日发布消息称,发现Android新漏洞,它使恶意应用程序得以绕过权限检查和现有的防护,访问系统广播信息。根据该通报,安全漏洞 CVE-2018-9489 不太可能得到任...

安卓绿色联盟
09/04
0
0
故意为之?安卓9.0以前的全部系统版本均受到“API-breaking”漏洞的影响

        Nightwatch Cybersecurity于8月29日发布消息称,发现Android新漏洞,它使恶意应用程序得以绕过权限检查和现有的防护,访问系统广播信息。根据该通报,这一漏洞的信息如下:  ...

嘶吼RoarTalk
09/07
0
0
Android手机新功能将支持视频聊天和面部识别

2011-07-09 22:26TAG: android开发 关键字:Android开发,手机网站制作 Android手机在不断地发展,新功能成出不穷——android开发, 就目前Android手机中已有多款第三方应用支持视频和语音聊...

sprinl
2011/07/10
0
0
android模拟器太慢怎么办?

开发的时候,模拟器实在太慢了,而且我的PC也变得很慢,写代码的时候上网查个东西都很慢,怎么办? 一个办法是买个android手机,这个日后再说; 另一个办法是virtualBox + Android x86;and...

mayqlzu
2013/01/31
0
0
Android之监测手机网络状态的广播

今天具体说下Android检测网络状态的广播,我们在做一些手机应用的时候如果网络发生改变可能会给用户造成一些损失,在中国2G,3G网络都没有普及的情况下,基本都是包流量的,所以在做一些视频...

程序袁_绪龙
2015/01/19
0
0

没有更多内容

加载失败,请刷新页面

加载更多

【大福利】极客时间专栏返现二维码大汇总

我已经购买了如下专栏,大家通过我的二维码你可以获得一定额度的返现! 然后,再给大家来个福利,只要你通过我的二维码购买,并且关注了【飞鱼说编程】公众号,可以加我微信或者私聊我,我再...

飞鱼说编程
今天
1
0
Spring5对比Spring3.2源码之容器的基本实现

最近看了《Spring源码深度解析》,该书是基于Spring3.2版本的,其中关于第二章容器的基本实现部分,目前spring5的实现方式已有较大改变。 Spring3.2的实现: public void testSimpleLoad(){...

Ilike_Java
今天
1
0
【王阳明心学语录】-001

1.“破山中贼易,破心中贼难。” 2.“夫万事万物之理不外于吾心。” 3.“心即理也。”“心外无理,心外无物,心外无事。” 4.“人心之得其正者即道心;道心之失其正者即人心。” 5.“无...

卯金刀GG
今天
2
0
OSChina 周三乱弹 —— 我们无法成为野兽

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @ _刚刚好: 霸王洗发水这波很骚 手机党少年们想听歌,请使劲儿戳(这里) hahahahahahh @嘻酱:居然忘了喝水。 让你喝可乐的话, 你准忘不了...

小小编辑
今天
10
0
vm GC 日志 配置及查看

-XX:+PrintGCDetails 打印 gc 日志 -XX:+PrintTenuringDistribution 监控晋升分布 -XX:+PrintGCTimeStamps 包含时间戳 -XX:+printGCDateStamps 包含时间 -Xloggc:<filename> 可以将数据保存为......

Canaan_
昨天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部