HttpURLConnection详解

1前言

Android将会在最新版本(API level 23,Android M)移除对HttpClient的支持,改为使用HttpURLConnection来代替HttpClient。因为HttpURLConnection因为使用了压缩传输和响应报文缓存的技术让它有了更少的流量和电量消耗。因此我们在这里探讨一下HttpURL的详细内容。

2Http报文详解

既然要使用HttpURLConnection代替HttpClient行使网络数据交互的作用首先肯定要了解HTTP报文格式。掌握了HTTP的报文格式,在使用代码组包的时候会更清楚的了解将会发送到服务器的数据内容。 关于HTTP报文详细格式参考:OSChina HTTP报文详解 和 CSDN HTTP请求报文和响应报文
简单来说HTTP请求报文分三部分,分别是请求行,请求头,请求体,同样的响应报文也分三部分:响应行,响应头和响应体。我们要做的是通过code组织可以让服务器识别的请求并且接收和解析服务器的响应内容。
下图表示Http请求报文和响应报文的示例:
HttpURLConnection详解_第1张图片

HttpURLConnection详解_第2张图片
图片引用自网络,侵删。

3,示例代码

一段简单的同服务器交互的代码,这段代码的功能是通过手机号查询归属地:
urlConnection = (HttpURLConnection) new URL("http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx/getMobileCodeInfo").openConnection();
//获取HttpURLConnection实例,这里根据协议应该是获取sun.net.www.protocol.http.HttpURLConnection实例
String parms = "mobileCode=18633483157&userID=";//等待被写入请求体的参数
urlConnection.setDoOutput(true);
urlConnection.setDoInput(true);
urlConnection.setRequestMethod("POST");//设置请求方法
urlConnection.setRequestProperty("Content-Length", parms.length()+"");//设置请求头,这里请求头必选字段内容以及含义需要和服务器做好约定
urlConnection.connect();//建立与服务器的连接
OutputStream outputStream = urlConnection.getOutputStream();
 
outputStream.write(parms.getBytes());
outputStream.flush();//写入参数
InputStream inputStream = urlConnection.getInputStream();//获取服务器的返回结果,注意在这个时候放在outputstream的参数才会正式上行到达服务器。
int resCode = urlConnection.getResponseCode();

综合上面报文示例,我们可以总结如下:
urlConnection.setRequestMethod("POST");
//设定请求方法
urlConnection.setRequestProperty("Content-Length", parms.length()+"");
//设定请求头
urlConnection.setDoOutput(true);
OutputStream outputStream = urlConnection.getOutputStream();
outputStream.write(parms.getBytes());
outputStream.flush();
//设定请求报文内容
urlConnection.getResponseCode();
//获取响应码(比如200请求处理成功等)
urlConnection.getResponseMessage();
//获取响应状态描述
urlConnection.getHeaderField("");
//获取响应头内容,根据响应头域名称获取对应值
urlConnection.getInputStream();
//获取响应消息体,一般需要解析内容并做显示

4,HttpURLConnection的类结构与数据结构(code来源:openjdk 7)


4.1 类结构图

URLConnection是所有urlconnection的顶层接口,不同子类根据自己的协议实现对应的逻辑,因此一定要在初始化阶段搞明白当前协议类型以及对应的URLConnection子类。

HttpURLConnection详解_第3张图片


4.2 数据结构

URLConnection::MessageHeaders request;通过两个String数组分别保存请求头数据中的字段名和字段值,通过set方法和grow方法存储值和保持自增长。同时在针对协议的具体实现中(比如sun.net.www.protocol.http.HttpURLConnection.java针对http协议的实现)定义了MessageHeader response成员,通过parseHeader方法从服务器响应数据(InputStream)中解析响应头并存入String数组中。
我们在代码中通过setRequestPropertity方法设定请求头的内容。
MessageHeaders定义:
class MessageHeader {
    private String keys[];
    private String values[];
    private int nkeys;
    /** grow the key/value arrays as needed */
 
    private void grow() {
        if (keys == null || nkeys >= keys.length) {
            String[] nk = new String[nkeys + 4];
            String[] nv = new String[nkeys + 4];
            if (keys != null)
                System.arraycopy(keys, 0, nk, 0, nkeys);
            if (values != null)
                System.arraycopy(values, 0, nv, 0, nkeys);
            keys = nk;
            values = nv;
        }
    }
     public synchronized void set(String k, String v) {
        for (int i = nkeys; --i >= 0;)
            if (k.equalsIgnoreCase(keys[i])) {
                values[i] = v;
                return;
            }
        add(k, v);
    }
     /** Parse a MIME header from an input stream. */
    public void parseHeader(InputStream is) throws java.io.IOException {
        synchronized (this) {
            nkeys = 0;
        }
        mergeHeader(is);
    }
}

设定请求头
public void setRequestProperty(String key, String value) {
        if (connected)
            throw new IllegalStateException("Already connected");
        if (key == null)
            throw new NullPointerException ("key is null");
 
        if (requests == null)
            requests = new MessageHeader();
 
        requests.set(key, value);
    }

响应信息:
responseCode和responseMessage以及针对协议的HttpURLConnection实现中定义的response成员都是用来保存解析过的服务器返回信息。
一个典型的返回信息如下:
HTTP/1.1 200 OK\r\n
  Server: nginx/1.4.7\r\n
  Date: Thu, 14 May 2015 06:47:26 GMT\r\n    
  Content-Type: text/html;charset=UTF-8\r\n
  Content-Length: 883\r\n

其中第一行200会被解析作为responseCode,OK被作为responseMessage内容。下面各个字段以key-value对的形式存入到response中。

交互控制信息:

通过定义如下信息控制交互过程中的行为,我们在code中也可以通过setXXX的形式设定这些控制选项。
protected URL url;
protected boolean doInput = true;
protected boolean doOutput = false;
protected boolean allowUserInteraction;
protected boolean useCaches = defaultUseCaches;
protected long ifModifiedSince = 0;
protected boolean connected = false;
private int connectTimeout;
private int readTimeout;
private static boolean fileNameMapLoaded = false;


你可能感兴趣的:(HttpURLConnection详解)