一)使用模式
HttpURLConnection 是一个HTTP协议的URLconnection,用来发送和接收网络上的数据。使用模式如下:
1. 调用 URL.openConnection()并强制转换结果为HTTPURLConnection类来获取一个新的HTTPURLConnection.
2. 准备请求数据。 请求的主要属性是URI, 请求头也可以包含证书, content types, 会话cookies等。
3. 上传请求数据(可选)。配置setDoOutput(true), 则可以上传请求数据。通过将请求数据写入getOutputstream()返回的流来实现。
4. 读取应答数据。 应答头通常都包含元数据,如应答主题的content type和长度, 修改时间和会话cookies等。 可以通过读取getInputStream()的返回值来获得应答主体。 如果应答主体为空,则返回空的数据流。
5. 断开连接。调用disconnect() 释放连接,该连接会被关闭或复用。
下述代码用来获取网页http://www.android.com/:
URL url = new URL("http://www.android.com/");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
readStream(in);
finally {
urlConnection.disconnect();
}
}
二)使用HTTPS实现安全的连接
使用“https"模式调用openConnection()打开URL,会返回一个HttpsURLConnection,它允许覆盖默认的HostnameVerifier和SSLSocketFatory. 从SSLContext中创建的SSLSokectFactory 会提供一个定制的X509TruestManager(用来验证证书链)和一个定制的X509KeyManager(提供客户端证书)。 具体见HttpsURLConnection
三)回复的处理
HttpURLConnection会跟踪5个HTTP跳转。 它会跟踪从原始服务器到另外服务器的跳转,但是无法从HTTPS到HTTP的跳转,或HTTP到HTTPS的跳转。
如果HTTP回复有错误发生,会抛出IOException, 使用getErrorStream()来读取异常。 正常情况下,使用getHeaderFields来读取头部数据。
四)上传请求数据
使用setDoOutput(true)配置连接。
为达到最好的性能,当数据长度确定时,可以调用setFixedLengthStreamingMode(int), 当数据不确定时,使用setChunkedStreamingMode(int). 否则,HttpURLConnection会在数据发送前,被迫缓冲完整的数据在内存中,浪费堆空间和增加不稳定性。
示例代码如下:
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
urlConnection.setDoOutput(true);
urlConnection.setChunkedStreamingMode(0);
OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
writeStream(out);
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
readStream(in);
finally {
urlConnection.disconnect();
}
}
五)性能
HTTPURLConnection返回的输入流和输出流不是缓存的。因此在调用需要使用BufferedInputStream或BufferedOutputStream来封装返回的数据流。 当从服务器上传或下载大量数据时, 使用流来限制内存中的数据大小。 除非你需要整个主体数据都在内存中,否则使用流来处理数据(而不是使用bytearray或string来存储完整的主体数据)。
该类会复用Socket来处理多个请求/回复。因此HTTP连接会比实际的需求持有更长时间。可以通过disconnect()来将socket返回到socket池中。 在发生HTTP请求前, 设置http.keepAlive属性为false会禁止上述行为。 http.maxConnection属性可以用来控制每个服务器持有的空闲连接的数量。
默认情况下,HTTPURLConnection会要求server端使用gzip压缩数据,在调用getInputStream()时会自动解压缩该数据。 这种情况下,回复头中的Content-Encoding 和Content-Length会被清理掉。可以通过如下设置来取消gzip压缩:
urlConnection.setRequestProperty("Accept-Encoding", "identity");
getContentLength()返回传输的数据大小, 但是因为数据是压缩过的,不能用了预测getInputStream()中需要读出的数据大小。因此,应该使用read()函数返回值是-1来判断数据流的结束。
六)处理网络登录
有些WIFI网络需要用户登录后才连接互联网。这样的登录网页通常使用HTTP跳转来展示。 使用getURL()测试连接是否被跳转,该检查只有在回复头被接收后才有效, 可以通过调用getHeaderFields()或getInputStream()来确保回复头被接收。下面是检查回复是否被跳转的代码:
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
if (!url.getHost().equals(urlConnection.getURL().getHost())) {
// we were redirected! Kick the user out to the browser to sign on?
...
} finally {
urlConnection.disconnect();
}
}
七)HTTP 认证
HttpURLConnection 支持HTTP basic authentication. 使用Authenticator 来设置认证处理器:
Authenticator.setDefault(new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password.toCharArray());
});
}
除非配合HTTPS使用,这不是一个安全的用户认证机制。 用户名,密码,请求和回复手机都是明文传输的。
七)使用Cookies
为在客户端和服务端之间创建和维持一个长会话, HttpURLConnection 包含一个可扩展的cookie管理器。 使用CookieHandler 和 CookieManager 来创建cookie管理系统:
CookieManager cookieManager = new CookieManager();
CookieHandler.setDefault(cookieManager);
默认情况下,CookieManager 只接收原始服务器的cookie. 另外两个已经实现的策略是:ACCEPT_ALL 和 ACCEPT_NONE. 可以通过实现CookiePolicy 来定制策略。
默认CookieManager保存所有接收的cookie在内存总, 通过实现CookieStore可以定制cookie存储。
处理HTTP回复设置cookie外, 也可以通过代码来设置。cookie必现包含域和路径属性,以便包含在请求头中。
默认情况下,HttpCookie只支持符合RFC 2965 规范的服务器。很多网络服务器支持早期版本RFC 2109。 为保持兼容,设置cookie版本为0.
例如,接收法语版的www.twitter.com:
HttpCookie cookie = new HttpCookie("lang", "fr");
cookie.setDomain("twitter.com");
cookie.setPath("/");
cookie.setVersion(0);
cookieManager.getCookieStore().add(new URI("http://twitter.com/"), cookie);
八)HTTP 方法
HttpURLConnection默认使用GET方法。 调用setDoOutput(true) 后默认使用POST方法。其他HTTP方法(OPTIONS, HEAD, PUT, DELETE 和TRACE)通过setRequestMethod(String)来设置。
九)代理
可以通过HTTP 或SOCKS 代理来连接。 使用URL.openConnection(Proxy)来创建使用代理的连接。
十)IPv6 支持
对同时有IPv4和IPv6的主机, 该类会试着连接两个地址直到连接建立。
十一)对回复的缓存
Android 4.0(Ice Cream Sandwich, API level 15)开始包含回复缓存。具体见android.net.http.HttpResponseCache。