Android HttpClient HttpUrlConnection用法总结

来源:互联网 发布:淘宝网红棉太极棉鞋 编辑:程序博客网 时间:2024/06/07 06:52

HttpClient

这个不用说了,Apache的API,但是不推荐使用了,在最新的api中甚至都把HttpClient去掉了。但是还是有必要掌握下HttpClient的用法的

GET方式

//先将参数放入List,再对参数进行URL编码List<BasicNameValuePair> params = new LinkedList<BasicNameValuePair>();params.add(new BasicNameValuePair("param1", "中国"));params.add(new BasicNameValuePair("param2", "value2"));//对参数编码String param = URLEncodedUtils.format(params, "UTF-8");//baseUrl           String baseUrl = "http://ubs.free4lab.com/php/method.php";//将URL与参数拼接HttpGet getMethod = new HttpGet(baseUrl + "?" + param);HttpClient httpClient = new DefaultHttpClient();try {    HttpResponse response = httpClient.execute(getMethod); //发起GET请求    Log.i(TAG, "resCode = " + response.getStatusLine().getStatusCode()); //获取响应码    Log.i(TAG, "result = " + EntityUtils.toString(response.getEntity(), "utf-8"));//获取服务器响应内容} catch (ClientProtocolException e) {    // TODO Auto-generated catch block    e.printStackTrace();} catch (IOException e) {    // TODO Auto-generated catch block    e.printStackTrace();}

POST方法

//和GET方式一样,先将参数放入Listparams = new LinkedList<BasicNameValuePair>();params.add(new BasicNameValuePair("param1", "Post方法"));params.add(new BasicNameValuePair("param2", "第二个参数"));try {    HttpPost postMethod = new HttpPost(baseUrl);    postMethod.setEntity(new UrlEncodedFormEntity(params, "utf-8")); //将参数填入POST Entity中    HttpResponse response = httpClient.execute(postMethod); //执行POST方法    Log.i(TAG, "resCode = " + response.getStatusLine().getStatusCode()); //获取响应码    Log.i(TAG, "result = " + EntityUtils.toString(response.getEntity(), "utf-8")); //获取响应内容} catch (UnsupportedEncodingException e) {    // TODO Auto-generated catch block    e.printStackTrace();} catch (ClientProtocolException e) {    // TODO Auto-generated catch block    e.printStackTrace();} catch (IOException e) {    // TODO Auto-generated catch block    e.printStackTrace();}

HttpClient传递复杂的参数,比如文件 需要额外的jar包

常见问题

异常处理
协议异常ClientProtocolException: 无效的cookie 很多http请求需要提供登录凭证 如果没有则协议异常
连接超时SocketTimeoutException: 无法连接到服务器比如服务器不可用 那么就连接超时
套接字超时ConnectTimeoutException: 既定时间内未收到服务器响应此时可以连接到服务器 但是未收到响应 那么套接字超时

HttpConnectionparam.setconnectiontimeout(param,5000)  //连接超时时间HttpConnectionparam.setsotimeout(param,5000) //套接字连接超时ConnManagerParams.settimeout(param,5000)  //连接管理器的超时 定义应用程序等待多久才让一个连接退出连接池的管理  比如连接池已经满了 新的连接就必须要等待了

使用try catch块来捕获

多线程问题
可以设置单例的httpclient 这样就可以共享设置的连接参数,但是单例的话 多线程就会有问题
HttpClient httpClient = new DefaultHttpClient(); 有多线程问题
比如两个线程都调用httpClient.execute(getMethod); getMethod使用的是同一个HttpGet对象 那么毫无疑问多线程问题

HttpConnectionparam.setconnectiontimeout(params,5000)HttpConnectionparam.setsotimeout(params,5000)ConnManagerParams.settimeout(params,5000)HttpClient httpClient = new DefaultHttpClient(ThreadSafeClientManager conMgr,HttpParams params);

ThreadSafeClientManager负责管理所有的httpclient的http连接 内部实现不会有多线程问题
此时的HttpParams作用在HttpClient上,所以可以供所有的HttpGet HttpPost对像共享

如果要定义自己的连接参数 那么可以

HttpGet getMethod = new HttpGet(baseUrl + "?" + param);HttpParams params= getMethod.getarams();HttpConnectionparam.setconnectiontimeout(param,5000);getMethod.setparams(params);

此时的HttpParams作用在HttpGet上,不会影响到HttpClient共享的连接参数

AndroidHttpClient

HttpClient子类 适用于android开发人员 连接超时/套接字超时默认20s 默认是线程安全的ThreadSafeClientManager

HttpUrlConnection

HttpUrlConnection属于Java的标准类库
更轻量了 推荐使用这个 4.4开始底层通过Okhttp来实现

HttpURLConnection的多线程问题? 因为采取Okhttp的底层实现,是木有多线程的问题的,具体是为什么,需要研究

HttpURLConnection使用

1. HttpURLConnection连接URL
1)创建一个URL对象
URL url = new URL(http://www.baidu.com);

2)利用HttpURLConnection对象从网络中获取网页数据
HttpURLConnection conn = (HttpURLConnection) url.openConnection();

3)设置连接超时
conn.setConnectTimeout(6*1000);

4)对响应码进行判断
if (conn.getResponseCode() != 200) //从Internet获取网页,发送请求,将网页以流的形式读回来
throw new RuntimeException(“请求url失败”);

5)得到网络返回的输入流
InputStream is = conn.getInputStream();
6)String result = readData(is, “GBK”); //文件流输入出文件用outStream.write
7)conn.disconnect();

总结:
- 记得设置连接超时,如果网络不好,Android系统在超过默认时间会收回资源中断操作.
- 返回的响应码200,是成功.
- 在Android中对文件流的操作和JAVA SE上面是一样的.
- 在对大文件的操作时,要将文件写到SDCard上面,不要直接写到手机内存上.
- 操作大文件是,要一遍从网络上读,一遍要往SDCard上面写,减少手机内存的使用.
- 对文件流操作完,要记得及时关闭.

2. 向Internet发送请求参数
步骤:
1)创建URL对象:URL realUrl = new URL(requestUrl);
2)通过HttpURLConnection对象,向网络地址发送请求
HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
3)设置容许输出:conn.setDoOutput(true);
4)设置不使用缓存:conn.setUseCaches(false);
5)设置使用POST的方式发送:conn.setRequestMethod(“POST”);
6)设置维持长连接:conn.setRequestProperty(“Connection”, “Keep-Alive”);
7)设置文件字符集:conn.setRequestProperty(“Charset”, “UTF-8”);
8)设置文件长度:conn.setRequestProperty(“Content-Length”, String.valueOf(data.length));
9)设置文件类型:conn.setRequestProperty(“Content-Type”,”application/x-www-form-urlencoded”);
10)以流的方式输出.
总结:
- 发送POST请求必须设置允许输出
- 不要使用缓存,容易出现问题.
- 在开始用HttpURLConnection对象的setRequestProperty()设置,就是生成HTML文件头.

3. 向Internet发送xml数据
XML格式是通信的标准语言,Android系统也可以通过发送XML文件传输数据.
1)将生成的XML文件写入到byte数组中,并设置为UTF-8:byte[] xmlbyte = xml.toString().getBytes(“UTF-8”);
2)创建URL对象,并指定地址和参数:URL url = new URL(http://localhost:8080/itcast/contanctmanage.do?method=readxml);
3)获得链接:HttpURLConnection conn = (HttpURLConnection) url.openConnection();
4)设置连接超时:conn.setConnectTimeout(6* 1000);
5)设置允许输出conn.setDoOutput(true);
6)设置不使用缓存:conn.setUseCaches(false);
7)设置以POST方式传输:conn.setRequestMethod(“POST”);
8)维持长连接:conn.setRequestProperty(“Connection”, “Keep-Alive”);
9)设置字符集:conn.setRequestProperty(“Charset”, “UTF-8”);
10)设置文件的总长度:conn.setRequestProperty(“Content-Length”, String.valueOf(xmlbyte.length));
11)设置文件类型:conn.setRequestProperty(“Content-Type”, “text/xml; charset=UTF-8”);
12)以文件流的方式发送xml数据:outStream.write(xmlbyte);
总结:
- 我们使用的是用HTML的方式传输文件,这个方式只能传输一般在5M一下的文件.
- 传输大文件不适合用HTML的方式,传输大文件我们要面向Socket编程.确保程序的稳定性
- 将地址和参数存到byte数组中:byte[] data = params.toString().getBytes();

HttpClient还是HttpUrlConnection

参考 Android访问网络,使用HttpURLConnection还是HttpClient?
在Android 2.2版本之前,HttpClient拥有较少的bug,因此使用它是最好的选择。
而在Android 2.3版本及以后,HttpURLConnection则是最佳的选择。它的API简单,体积较小,因而非常适用于Android项目。压缩和缓存机制可以有效地减少网络访问的流量,在提升速度和省电方面也起到了较大的作用。对于新的应用程序应该更加偏向于使用HttpURLConnection,因为在以后的工作当中我们也会将更多的时间放在优化HttpURLConnection上面。

其实现在嘛,两者都不用,就用Okhttp
HttpUrlConnection现在的底层实现就是通过Okhttp

HttpURLConnection java的标准类(java.net),什么都没封装,用起来太原始,不方便
HttpClient Apache开源框架,提供对HTTP协议访问的封装,包括http的请求头,参数,内容体,响应等及多线程的应用。
HttpClient方便,但是封装了太多,也可能导致网络请求速度变慢,灵活度不够
HttpClient就是一个增强版的HttpURLConnection ,HttpURLConnection可以做的事情 HttpClient全部可以做;HttpURLConnection没有提供的有些功能,HttpClient也提供了

Volley中两者的使用

我们知道Volley中api<=9使用的是HttpClientStack,内部使用HttpClient。api>9使用的是HurlStack,内部使用HttpUrlConnection

先来看HttpClientStack,使用起来很简单

    private static void addHeaders(HttpUriRequest httpRequest, Map<String, String> headers) {        for (String key : headers.keySet()) {            httpRequest.setHeader(key, headers.get(key));        }    }    @Override    public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)            throws IOException, AuthFailureError {        HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders);        addHeaders(httpRequest, additionalHeaders);  //缓存中的头        addHeaders(httpRequest, request.getHeaders()); //request中的设置的头        onPrepareRequest(httpRequest);        HttpParams httpParams = httpRequest.getParams();        int timeoutMs = request.getTimeoutMs();        // TODO: Reevaluate this connection timeout based on more wide-scale        // data collection and possibly different for wifi vs. 3G.        HttpConnectionParams.setConnectionTimeout(httpParams, 5000);        HttpConnectionParams.setSoTimeout(httpParams, timeoutMs);        return mClient.execute(httpRequest); //调用HttpClient的excute方法,执行网络请求,最后直接返回HttpResponse    }    static HttpUriRequest createHttpRequest(Request<?> request,            Map<String, String> additionalHeaders) throws AuthFailureError {            case Method.GET:                return new HttpGet(request.getUrl());            case Method.POST: {                HttpPost postRequest = new HttpPost(request.getUrl());                postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());                setEntityIfNonEmptyBody(postRequest, request); //设置post请求参数                return postRequest;            ........            }            default:                throw new IllegalStateException("Unknown request method.");        }    private static void setEntityIfNonEmptyBody(HttpEntityEnclosingRequestBase httpRequest,            Request<?> request) throws AuthFailureError {        byte[] body = request.getBody();        if (body != null) {            HttpEntity entity = new ByteArrayEntity(body);            httpRequest.setEntity(entity); //setEntity方法设置post请求参数        }    }

看吧,使用起来很方便简单,都是直接封装好了,,,下面来看HurlStack,使用起来就更负责了

   @Override    public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)            throws IOException, AuthFailureError {        String url = request.getUrl();        HashMap<String, String> map = new HashMap<String, String>();        map.putAll(request.getHeaders()); //取出request设置的head        map.putAll(additionalHeaders); //取出缓存中的Header,如果该request前面发起过网络请求,那么就会缓存下来,同时会把http的head也缓存        ........        URL parsedUrl = new URL(url);        HttpURLConnection connection = openConnection(parsedUrl, request); //初始化HttpURLConnection对象        for (String headerName : map.keySet()) {            connection.addRequestProperty(headerName, map.get(headerName)); //设置Http请求的head        }        setConnectionParametersForRequest(connection, request);        // Initialize HttpResponse with data from the HttpURLConnection.        ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);        int responseCode = connection.getResponseCode();        if (responseCode == -1) {            // -1 is returned by getResponseCode() if the response code could not be retrieved.            // Signal to the caller that something was wrong with the connection.            throw new IOException("Could not retrieve response code from HttpUrlConnection.");        }        StatusLine responseStatus = new BasicStatusLine(protocolVersion,                connection.getResponseCode(), connection.getResponseMessage());        BasicHttpResponse response = new BasicHttpResponse(responseStatus); //HttpResponse需要自己创建        if (hasResponseBody(request.getMethod(), responseStatus.getStatusCode())) {            response.setEntity(entityFromConnection(connection)); //调用HttpResponse的setEntity方法设置相应内容        }        for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {            if (header.getKey() != null) {                Header h = new BasicHeader(header.getKey(), header.getValue().get(0));                response.addHeader(h); //调用HttpResponse的addHeader方法添加响应头            }        }        return response;    }    private HttpURLConnection openConnection(URL url, Request<?> request) throws IOException {        HttpURLConnection connection = createConnection(url);        int timeoutMs = request.getTimeoutMs();        connection.setConnectTimeout(timeoutMs); //设置连接超时时间        connection.setReadTimeout(timeoutMs);         connection.setUseCaches(false); //不使用缓存?        connection.setDoInput(true); //允许输出        // use caller-provided custom SslSocketFactory, if any, for HTTPS        if ("https".equals(url.getProtocol()) && mSslSocketFactory != null) {            ((HttpsURLConnection)connection).setSSLSocketFactory(mSslSocketFactory);        }        return connection;    }    //可以看到volley支持get,post,PUT等都支持的,符合http规范    static void setConnectionParametersForRequest(HttpURLConnection connection,            Request<?> request) throws IOException, AuthFailureError {        switch (request.getMethod()) {            case Method.GET:                // Not necessary to set the request method because connection defaults to GET but                // being explicit here.                connection.setRequestMethod("GET");                break;            case Method.POST:                connection.setRequestMethod("POST");                addBodyIfExists(connection, request);            ...........        }    }    private static void addBodyIfExists(HttpURLConnection connection, Request<?> request)            throws IOException, AuthFailureError {        byte[] body = request.getBody();        if (body != null) {            connection.setDoOutput(true);            connection.addRequestProperty(HEADER_CONTENT_TYPE, request.getBodyContentType()); //request的getBodyContentType()方法可以设置Content-Type请求头            DataOutputStream out = new DataOutputStream(connection.getOutputStream());            out.write(body); //把getBody()返回的byte[]数组写入输入流,            out.close();        }    }    private static HttpEntity entityFromConnection(HttpURLConnection connection) {        BasicHttpEntity entity = new BasicHttpEntity();        InputStream inputStream;        try {            inputStream = connection.getInputStream();        } catch (IOException ioe) {            inputStream = connection.getErrorStream();        }        entity.setContent(inputStream); //把响应内容写入HttpEntity        entity.setContentLength(connection.getContentLength());        entity.setContentEncoding(connection.getContentEncoding());        entity.setContentType(connection.getContentType());        return entity;    }

看到两者的区别了吧?
HttpClient使用起来很简单

  1. mClient.execute(httpRequest); 直接返回HttpResponse对象,这个对象封装了响应内容和响应头
  2. httpRequest.setHeader(key, headers.get(key)); 给请求添加头
  3. HttpEntity entity = new ByteArrayEntity(request.getBody()); httpRequest.setEntity(entity); //给请求添加post参数

HttpURLConnection使用麻烦多了
HttpResponse对象需要自己创建,并手动添加响应内容和响应头,这里创建的是BasicHttpResponse实现了HttpResponse接口

  1. connection.addRequestProperty(headerName, map.get(headerName)); //设置Http请求的head
  2. DataOutputStream out = new DataOutputStream(connection.getOutputStream()); out.write(request.getBody()); //给请求添加post参数
  3. response.addHeader(h); //调用HttpResponse的addHeader方法添加响应头
  4. response.setEntity(entityFromConnection(connection)); //调用HttpResponse的setEntity方法设置相应内容
0 0
原创粉丝点击