一直以来我都认为,HttpURLConnection是Java中对网络相关原生的实现,可以说用他来模拟做Http请求就是官方版本的 HttpClient实现。个人比较崇尚官方的东西,但是在使用中发现HttpURLConnection的应用很容易让人造成困扰,本文对该部分技术的 使用经验做一定的总结,以作备忘之用。

 

关于流的使用

 

 

conn.getOutputStream()
conn.getInputStream()

在使用输入输出流的时候,往往会错误的认为

conn.getOutputStream()调用时会相应的发出请求,而在conn.getInputStream()用来读取服务器响应。但是,事实是:

请求只在conn.getInputStream()被调用时才会被发出

这个过程很让人郁闷,因为这样直接导致了编码时流程上控制的混乱。

因为以前一直认为流的操作往往时随着代码的执行而同步传输的,但是在这里情况似乎不是这样。

 

关于参数传递

在发送HTTP请求时,我们常用的都是GET和POST,一般会用conn.setRequestMethod来控制发送的类型,在默认情况下使用的是GET

我常犯的一个错误就是在conn.setRequestMethod(“GET”);后,再次调用conn.setDoOutput(true), 这个方法会导致发出去的请求类型变成POST,而忽略setRequestMethod。这个原因在于,setDoOutput等于告诉了JVM需要进行 数据的传递,而这个传递是在请求正文中的(该段说明可能不是非常正确,还需更进一步推敲,因为我认为GET请求其实也是在请求正文中的)

 

关于Cookie解析

在模拟请求中Cookie的功能不言而喻,因为在 一些站点上Cookie的值会随同请求一起发出,因此当服务器返回Cookie时,一定要全部抓住保存下来,那么Cookie在保存时应该保存成什么样的 数据格式就值得探讨了。众所周知的是Cookie是key-value的键值对,但是在真实的请求头中,全部都是纯文本,以下是一段Cookie在 Response中的例子。

 

session-id=-; path=/; domain=.www.amazon.cn; expires=Tue, 15-Jun-1999 16:49:18 GMT

 

很明显是一段session-id的本地化保存。由于每个cookie都有3个属性

path

domain

expires

这3个属性代表了cookie的作用域。

根据这个作用域,我设计了如下的数据结构来存储所有的cookie

 

Map<String, Map<String, String[]>>

KEY的String代表Domain,因为cookie的主要作用范围是以Domain来划分的,而VALUE也是个Map

 

他的Key代表属性名,其Value代表的是该属性的path, domain,expires,我认为这个结构很好的描述了cookie的结构。

以下一段将cookie的长串字符串,写入该map的一段方法。算法有待改进。

 

private void adaptCookieStr(String setCookieStr) {
    System.out.println(setCookieStr);
    String[] cookieValueEquals = setCookieStr.split(";\\s*");
    String[] cookieValueArray = new String[cookieValueEquals.length];
    String domain = "";
    String cookieName = "";

    for (int i = 0; i < cookieValueEquals.length; i++) {
        String cookieValueEqual = cookieValueEquals[i];
        String[] eqArray = cookieValueEqual.split("=");
        if ("domain".equalsIgnoreCase(eqArray[0])) {
            domain = eqArray[1];
        }
        if (!"domain".equalsIgnoreCase(eqArray[0]) && !"expires".equalsIgnoreCase(eqArray[0]) && !"path".equalsIgnoreCase(eqArray[0])) {
            cookieName = eqArray[0];
        }
        cookieValueArray[i] = eqArray[1];
    }
    if (cookieMap.get(domain) != null) {
        cookieMap.get(domain).put(cookieName, cookieValueArray);
    } else {
        Map<String, String[]> cookieValueMap = new LinkedHashMap<String, String[]>();
        cookieValueMap.put(cookieName, cookieValueArray);
        cookieMap.put(domain, cookieValueMap);
    }
}