zoukankan      html  css  js  c++  java
  • Java Android HTTP实现总结

     

    Java Android HTTP实现总结

      Http(Hypertext Transfer Protocol)超文本传输协议,是一个基于请求/响应模式的无状态的协议,Http1.1版给出了持续连接的机制,客户端建立连接之后,可以发送多次请求,当不会再发送时再关闭连接。

     

      Android使用Java,对于Http协议的基本功能有两种实现方案:

      1.使用JDK的java.net包下的HttpURLConnection.

      2.使用Apache的HttpClient

      关于二者的比较可以看一下:

      http://www.cnblogs.com/devinzhang/archive/2012/01/17/2325092.html

     

      Android SDK中集成了Apache的HttpClient模块,也即说Android上两种方法都能用。

      之前看一个Android开发者博客(原文链接先空缺,需要翻墙)对此的讨论,大意总结如下:

      1.HttpClient的功能比较全,更加强大;而HttpURLConnection的功能较简单和原始,但是性能更好。

      2.在Android 2.x的版本中使用HttpURLConnection有bug,但是后来高级版本的Android已经将带来的bug修复,并且做了一些进一步优化的工作,所以建议在高级版本的Android系统(Android 2.3之后)使用HttpURLConnection,低版本的系统仍使用HttpClient。

    程序实现

      下面来讨论一下实现,首先,需要确认Manifest中有权限:

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

    使用JDK的HttpURLConnection类

      HttpURLConnection参考:

      http://developer.android.com/reference/java/net/HttpURLConnection.html

      使用这个类的一般步骤:

      1.通过URL.openConnection() 方法获取一个HttpURLConnection对象,并且将结果强制转化为HttpURLConnection类型。

      2.准备请求(prepare the request),包括URI,headers中的各种属性等

      (Request headers may also include metadata such as credentials, preferred content types, and session cookies.)

      3.请求体(optionally)。如果有请求体那么setDoOutput(true)必须为true,然后把输入放在getOutputStream()流中。

      4.读取响应。响应的headers一般包括了一些metadata比如响应体的内容类型和长度,修改日期以及session cookies。响应体可以从 getInputStream()流中读出。

      5.断开连接。响应体被读出之后,应该调用 disconnect()方法来断开连接。

      例子代码:

    package com.example.helloandroidhttp;
    
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.io.UnsupportedEncodingException;
    import java.net.HttpURLConnection;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.net.URLEncoder;
    import java.util.Map;
    
    import android.util.Log;
    
    public class HttpUtilsJDK {
        private static final String LOG_TAG = "Http->JDK";
        private static final int CONNECT_TIME_OUT = 3000;
        private static final String HEADER_CONTENT_TYPE = "Content-Type";
        private static final String HEADER_CONTENT_LENGTH = "Content-Length";
        /**
         * Default encoding for POST or PUT parameters. See
         * {@link #getParamsEncoding()}.
         */
        private static final String DEFAULT_PARAMS_ENCODING = "UTF-8";
    
        public static String getParamsEncoding() {
            return DEFAULT_PARAMS_ENCODING;
        }
    
        public static String getBodyContentType() {
            return "application/x-www-form-urlencoded; charset="
                    + getParamsEncoding();
        }
    
        public static String performGetRequest(String baseUrl) {
            String result = null;
            HttpURLConnection connection = null;
            try {
                URL url = new URL(baseUrl);
                if (null != url) {
    
                    // 获取HttpURLConnection类型的对象
                    connection = (HttpURLConnection) url.openConnection();
                    // 设置连接的最大等待时间
                    connection.setConnectTimeout(CONNECT_TIME_OUT);
    
                    // Sets the maximum time to wait for an input stream read to
                    // complete before giving up.
                    connection.setReadTimeout(3000);
                    // 设置为GET方法
                    connection.setRequestMethod("GET");
                    connection.setDoInput(true);
    
                    if (200 == connection.getResponseCode()) {
                        InputStream inputStream = connection.getInputStream();
    
                        result = getResultString(inputStream, getParamsEncoding());
                    }
                    else {
                        Log.e(LOG_TAG,
                                "Connection failed: "
                                        + connection.getResponseCode());
                    }
    
                }
            }
            catch (MalformedURLException e) {
                e.printStackTrace();
            }
            catch (IOException e) {
                e.printStackTrace();
            }
            finally {
                connection.disconnect();
            }
    
            return result;
        }
    
        public static String performPostRequest(String baseUrl,
                Map<String, String> params) {
            String result = null;
            HttpURLConnection connection = null;
            try {
                URL url = new URL(baseUrl);
                if (null != url) {
                    // 获取HttpURLConnection类型的对象
                    connection = (HttpURLConnection) url.openConnection();
                    // 设置响应超时限制
                    connection.setConnectTimeout(CONNECT_TIME_OUT);
                    // 设置为POST方法
                    connection.setRequestMethod("POST");
                    connection.setDoInput(true);
                    // 有请求体则setDoOutput(true)必须设定
                    connection.setDoOutput(true);
    
                    // 为了性能考虑,如果包含请求体,那么最好调用 setFixedLengthStreamingMode(int)或者
                    // setChunkedStreamingMode(int)
                    // connection.setChunkedStreamingMode(0);// 参数为0时使用默认值
    
                    byte[] data = getParamsData(params);
    
                    connection.setRequestProperty(HEADER_CONTENT_TYPE,
                            getBodyContentType());
                    if (null != data) {
                        connection.setFixedLengthStreamingMode(data.length);
                        connection.setRequestProperty(HEADER_CONTENT_LENGTH,
                                String.valueOf(data.length));
                        OutputStream outputStream = connection.getOutputStream();
                        outputStream.write(data);
                    }
    
                    // 得到返回值
                    int responseCode = connection.getResponseCode();
                    if (200 == responseCode) {
                        result = getResultString(connection.getInputStream(),
                                getParamsEncoding());
    
                    }
                    else {
                        Log.e(LOG_TAG,
                                "Connection failed: "
                                        + connection.getResponseCode());
                    }
    
                }
            }
            catch (MalformedURLException e) {
                e.printStackTrace();
            }
            catch (IOException e) {
                e.printStackTrace();
            }
            finally {
                connection.disconnect();
            }
    
            return result;
        }
    
        private static byte[] getParamsData(Map<String, String> params) {
            byte[] data = null;
    
            try {
                if (null != params && !params.isEmpty()) {
                    StringBuffer buffer = new StringBuffer();
    
                    for (Map.Entry<String, String> entry : params.entrySet()) {
    
                        buffer.append(entry.getKey())
                                .append("=")
                                .append(URLEncoder.encode(entry.getValue(),
                                        getParamsEncoding())).append("&");// 请求的参数之间使用&分割。
    
                    }
                    // 最后一个&要去掉
                    buffer.deleteCharAt(buffer.length() - 1);
    
                    data = buffer.toString().getBytes(getParamsEncoding());
                }
            }
            catch (UnsupportedEncodingException e) {
                e.printStackTrace();
    
            }
    
            return data;
        }
    
        private static String getResultString(InputStream inputStream, String encode) {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            byte[] data = new byte[1024];
            int len = 0;
            String result = "";
            if (inputStream != null) {
                try {
                    while ((len = inputStream.read(data)) != -1) {
                        outputStream.write(data, 0, len);
                    }
                    result = new String(outputStream.toByteArray(), encode);
    
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return result;
        }
    }
    HttpUtilsJDK

    使用Apache的HttpClient

      可以查看官方的Tutorial:

      http://hc.apache.org/httpcomponents-client-ga/tutorial/html/index.html

      Android有一个实现类AndroidHttpClient,实现了HttpClient

      http://developer.android.com/reference/android/net/http/AndroidHttpClient.html

      包装了一些默认的设置。

     

    关于HTTP entity

      HTTP消息中可以包含内容实体(content entity),可以看做消息的报文,包含在请求或者响应中。

      HTTP规范规定两种请求方法可以包含内容实体:POST和PUT。

      响应则通常是包含内容实体的。

      HttpClient会根据内容来源区分三种实体:

      1.streamed:内容来源是流,这类里包含了从HTTP响应中获得的实体,流式实体不可重复。

      2.self-contained:内容是从内存或者其他方式获得的,即和连接无关,这类实体是可以重复的,多数是用来放在HTTP请求中的实体。

      3.wrapping:这类实体是从其他实体获得的。

      对于用HttpClient创建的请求实体来说,streamed和self-contained类型的区别其实不太重要,建议把不可重复的实体看作是streamed的,可重复的看作是self-contained的。

    创造实体内容

      为了发送HTTP的POST请求(当然还有PUT请求也有实体),需要把一些参数放在实体中,创造实体内容,有四个类型的类可选用:

      StringEntity, ByteArrayEntity, InputStreamEntity, FileEntity

      注意其中的InputStreamEntity是不可重复的。

     

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

      两个键值对,被UrlEncodedFormEntity实例编码后变为如下内容:

    param1=value1&param2=value2

      

      使用Apache的HttpClient发送HTTP请求的辅助类,例子代码:

    package com.example.helloandroidhttp;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.UnsupportedEncodingException;
    import java.net.URLEncoder;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    
    import org.apache.http.HttpEntity;
    import org.apache.http.HttpResponse;
    import org.apache.http.NameValuePair;
    import org.apache.http.client.HttpClient;
    import org.apache.http.client.entity.UrlEncodedFormEntity;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.entity.ByteArrayEntity;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.impl.client.DefaultHttpClient;
    import org.apache.http.message.BasicNameValuePair;
    import org.apache.http.params.BasicHttpParams;
    import org.apache.http.params.HttpConnectionParams;
    import org.apache.http.params.HttpParams;
    
    import android.util.Log;
    
    public class HttpUtilsApache {
    
        private static final String LOG_TAG = "Http->Apache";
        private static final String HEADER_CONTENT_TYPE = "Content-Type";
        /**
         * Default encoding for POST or PUT parameters. See
         * {@link #getParamsEncoding()}.
         */
        private static final String DEFAULT_PARAMS_ENCODING = "UTF-8";
    
        /**
         * Returns which encoding should be used when converting POST or PUT
         * parameters returned by {@link #getParams()} into a raw POST or PUT body.
         *
         * <p>
         * This controls both encodings:
         * <ol>
         * <li>The string encoding used when converting parameter names and values
         * into bytes prior to URL encoding them.</li>
         * <li>The string encoding used when converting the URL encoded parameters
         * into a raw byte array.</li>
         * </ol>
         */
        public static String getParamsEncoding() {
            return DEFAULT_PARAMS_ENCODING;
        }
    
        public static String getBodyContentType() {
            return "application/x-www-form-urlencoded; charset="
                    + getParamsEncoding();
        }
    
        public static String performGetRequest(String url) {
    
            String result = null;
            // 生成一个请求对象
            HttpGet httpGet = new HttpGet(url);
    
            // 1.生成一个Http客户端对象(带参数的)
            HttpParams httpParameters = new BasicHttpParams();
            HttpConnectionParams.setConnectionTimeout(httpParameters, 10 * 1000);// 设置请求超时10秒
            HttpConnectionParams.setSoTimeout(httpParameters, 10 * 1000); // 设置等待数据超时10秒
            HttpConnectionParams.setSocketBufferSize(httpParameters, 8192);
    
            HttpClient httpClient = new DefaultHttpClient(httpParameters); // 此时构造DefaultHttpClient时将参数传入
            // 2.默认实现:
            // HttpClient httpClient = new DefaultHttpClient();
            httpGet.addHeader(HEADER_CONTENT_TYPE, getBodyContentType());
    
            // 下面使用Http客户端发送请求,并获取响应内容
    
            HttpResponse httpResponse = null;
    
            try {
                // 发送请求并获得响应对象
                httpResponse = httpClient.execute(httpGet);
    
                final int statusCode = httpResponse.getStatusLine().getStatusCode();
                if (200 == statusCode) {
                    result = getResponseString(httpResponse);
                }
                else {
                    Log.e(LOG_TAG, "Connection failed: " + statusCode);
                }
    
            }
            catch (Exception e) {
                e.printStackTrace();
            }
            finally {
    
            }
    
            return result;
        }
    
        public static String performPostRequest(String baseURL, String postData) {
            String result = "";
            HttpResponse response = null;
            try {
    
                // URL使用基本URL即可,其中不需要加参数
                HttpPost httpPost = new HttpPost(baseURL);
                // 设置ContentType
                httpPost.addHeader(HEADER_CONTENT_TYPE, getBodyContentType());
    
                // 将请求体内容加入请求中
                HttpEntity requestHttpEntity = prepareHttpEntity(postData);
    
                if (null != requestHttpEntity) {
                    httpPost.setEntity(requestHttpEntity);
                }
    
                // 需要客户端对象来发送请求
                HttpClient httpClient = new DefaultHttpClient();
                // 发送请求
                response = httpClient.execute(httpPost);
    
                final int statusCode = response.getStatusLine().getStatusCode();
                if (200 == statusCode) {
                    // 显示响应
                    result = getResponseString(response);
                }
                else {
                    Log.e(LOG_TAG, "Connection failed: " + statusCode);
                }
    
            }
            catch (Exception e) {
                e.printStackTrace();
            }
            finally {
    
            }
    
            return result;
    
        }
    
        /**
         * 直接利用String生成HttpEntity,String应该已经是key=value&key2=value2的形式
         *
         * @param postData
         * @return
         */
        private static HttpEntity prepareHttpEntity(String postData) {
    
            HttpEntity requestHttpEntity = null;
    
            try {
    
                if (null != postData) {
                    // 去掉所有的换行
                    postData = postData.replace("
    ", "");
                    // one way
                    // requestHttpEntity = new ByteArrayEntity(
                    // postData.getBytes(getParamsEncoding()));
    
                    // another way
                    requestHttpEntity = new StringEntity(postData,
                            getParamsEncoding());
                    ((StringEntity) requestHttpEntity)
                            .setContentEncoding(getParamsEncoding());
                    ((StringEntity) requestHttpEntity)
                            .setContentType(getBodyContentType());
    
                }
            }
            catch (Exception e) {
                e.printStackTrace();
            }
            return requestHttpEntity;
        }
    
        /**
         * 利用Map结构的参数生成HttpEntity,使用UrlEncodedFormEntity对参数对进行编码
         *
         * @param params
         * @return
         */
        private static HttpEntity prepareHttpEntity1(Map<String, String> params) {
            // 需要将String里面的key value拆分出来
    
            HttpEntity requestHttpEntity = null;
            try {
    
                if (null != params) {
                    List<NameValuePair> pairList = new ArrayList<NameValuePair>(
                            params.size());
                    for (Map.Entry<String, String> entry : params.entrySet()) {
                        NameValuePair pair = new BasicNameValuePair(entry.getKey(),
                                entry.getValue());
                        pairList.add(pair);
                    }
                    requestHttpEntity = new UrlEncodedFormEntity(pairList,
                            getParamsEncoding());
    
                }
    
            }
            catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
    
            return requestHttpEntity;
        }
    
        /**
         * 利用Map结构的参数生成HttpEntity,使用自己的方法对参数进行编码合成字符串
         *
         * @param params
         * @return
         */
        private static HttpEntity prepareHttpEntity2(Map<String, String> params) {
            // 需要将String里面的key value拆分出来
    
            HttpEntity requestHttpEntity = null;
            byte[] body = encodeParameters(params, getParamsEncoding());
            requestHttpEntity = new ByteArrayEntity(body);
    
            return requestHttpEntity;
        }
    
        /**
         * Converts <code>params</code> into an application/x-www-form-urlencoded
         * encoded string.
         */
        private static byte[] encodeParameters(Map<String, String> params,
                String paramsEncoding) {
            StringBuilder encodedParams = new StringBuilder();
            try {
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    encodedParams.append(URLEncoder.encode(entry.getKey(),
                            paramsEncoding));
                    encodedParams.append('=');
                    encodedParams.append(URLEncoder.encode(entry.getValue(),
                            paramsEncoding));
                    encodedParams.append('&');
                }
                return encodedParams.toString().getBytes(paramsEncoding);
            }
            catch (UnsupportedEncodingException uee) {
                throw new RuntimeException("Encoding not supported: "
                        + paramsEncoding, uee);
            }
        }
    
        public static String getResponseString(HttpResponse response) {
            String result = null;
            if (null == response) {
                return result;
            }
    
            HttpEntity httpEntity = response.getEntity();
            InputStream inputStream = null;
            try {
                inputStream = httpEntity.getContent();
                BufferedReader reader = new BufferedReader(new InputStreamReader(
                        inputStream));
                result = "";
                String line = "";
                while (null != (line = reader.readLine())) {
                    result += line;
                }
            }
            catch (Exception e) {
                e.printStackTrace();
            }
            finally {
                try {
                    if (null != inputStream) {
                        inputStream.close();
                    }
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return result;
    
        }
    }
    HttpUtilsApache

     

    参考资料

      本博客HTTP标签下相关文章,比如这个:

      http://www.cnblogs.com/mengdd/p/3144599.html

      Apache HttpClient:

      http://hc.apache.org/httpcomponents-client-ga/

      http://hc.apache.org/httpcomponents-client-ga/tutorial/html/fundamentals.html#d5e49

     

      Android之网络编程 系列博文:

      http://www.cnblogs.com/devinzhang/category/349642.html

     

      Http Header详解:

      http://kb.cnblogs.com/page/92320/

      Android--Apache HttpClient:

      http://www.cnblogs.com/plokmju/p/Android_apacheHttpClient.html

     

    推荐项目

      Android网络通信框架Volley:

      https://github.com/mengdd/android-volley

      Android Asynchronous Http Client:A Callback-Based Http Client Library for Android

      https://github.com/mengdd/android-async-http

      也即:http://loopj.com/android-async-http/

      本文项目地址(目前还是个挺简陋的Demo,有待完善):

      https://github.com/mengdd/HelloAndroidHttpUtils

     

  • 相关阅读:
    【Web技术】561- 网站性能优化之度量篇
    【拓展】什么是Deno?跟Node.js有何区别?
    【Web技术】560- 一个简洁、有趣的无限下拉方案
    【Web技术】559- 一文带你彻底搞懂跨域
    【TS】558- 5000 多字,让你一文掌握 TS 枚举
    【拓展】你真的会写 Markdown 么?
    【调试】557- 11 个Chrome骚技巧让你为所欲为
    ios 地图
    ios 7 20像素解决
    保存图片到相册
  • 原文地址:https://www.cnblogs.com/mengdd/p/3607293.html
Copyright © 2011-2022 走看看