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

     

  • 相关阅读:
    C#磁吸屏幕窗体类库
    准备
    我写的诗
    How to turn off a laptop keyboard
    How to tell which commit a tag points to in Git?
    Why should I care about lightweight vs. annotated tags?
    How to get rid of “would clobber existing tag”
    Facebook, Google and Twitter threaten to leave Hong Kong over privacy law changes
    The need for legislative reform on secrecy orders
    Can a foreign key be NULL and/or duplicate?
  • 原文地址:https://www.cnblogs.com/mengdd/p/3607293.html
Copyright © 2011-2022 走看看