HttpURLConnection使用简介

一个拥有支持Http特性的URLConnection。详情看文档

按以下模式使用此类:

  1. 用URL.openConnection()获取一个HttpURLConnection实例并且把结果强转成HttpURLConnection

  2. 准备结果。返回内容最基本的就是它的URI.返回头包含了像证书,首选内容类型和session cookies之类的元数据。

  3. 随意上传请求体。例如必须用setDoOutput(true)配置,如果包含了请求体。依靠调用getOutputStream()写输出流来发送数据。

  4. 读取响应。响应头通常包含诸如body内容类型和长度,修改的数据session cookies之类的元数据。读取响应body可以调用getInputStream()从流中获取。如果相应没有body,这个方法返回空的stream.

  5. 断开连接。一旦响应body已经读取,HttpURLConnection需要通过调用disconnect()被关闭。断开连接释放了连接资源,这样它们可以被关闭或重用。

举个例子

   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安全连接

使用URL带上"https"调用openConnection()就会返回一个HttpsURLConnection对象,这个对象允许你覆盖默认的HostnameVerifierSSLSocketFactory。一个应用提供的由SSLContext创建的SSLSocketFactory,可以提供自定义的X509TrustManager给检验证书链,和一个自定义的X509KeyManager给客户端证书。详情请看HttpsURLConnection.

响应处理

HttpURLConnection会跟随HTTP的五个重定向。它会从原始的服务器重定向到另一个。这些形成不会从Https重定向到http或者相反。

如果http响应发生错误,getInputStream()会抛出IOException.使用getErrorStream()可以读取错误响应。可以用getHeaderFields()读取header.

发送内容

上传数据到一个web服务器,输出连接使用setDoOutput(true)配置。

想要最好的性能,你最好调用setFixedLengthStreamingMode(int),当事先知道body的长度,或者事先不知道,就调用setChunkedStreamingMode(int).否则HttpURLConnection会强制在它发送之前缓存请求的body在内存中,浪费(很有可能耗尽)堆内存。

举个例子,执行上传:

   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();
   }

性能

这个类返回的输入输出流没有缓存。调用者需要用BufferedInputStream或者BufferedOutputStream包裹一下。调用者只需要通过buffer读取块数据。当传输大量数据的时候,立刻用流stream限制在内存中的数据。除非你立即需要整个数据在内存中,把它加工成流stream(而不是用byte数组或string存储整个body)。

为了减少潜在因素,这个类会重用相同的socket来用于请求和响应。作为结果,HTTP连接可能保持开启状态超过必要的时间。调用disconnect()可以把socket交还给socket连接池。这个行为能够在进行分配http请求之前,利用http.keepAlive系统所有权取消设置。http.maxConnections所有权可能被用来控制许多无意义的连接

默认的,HttpURLConnection请求的实现,服务器使用gzip压缩,并且能通过调用getInputStream()自动解压缩数据。Content-Encoding和Content-Length响应头在这时被清除。能够通过在请求头设置可接受的编码,来取消gzip压缩。

urlConnection.setRequestProperty("Accept-Encoding", "identity");

明确地设置可接受的请求头可以取消自动的解压并且使响应头完好无损;调用者如果需要的话,必须根据响应头的Content-Encoding执行解压。

getContentLength()返回传输的字节数,不能从getInputStream()获取压缩数据有多少字节。相反,从stream里面获取数据,直到它耗尽为止,这时,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验证。用验证设置VM-wide验证管理:

Authenticator.setDefault(new Authenticator() {     
  protected PasswordAuthentication getPasswordAuthentication() {       
    return new PasswordAuthentication(username, password.toCharArray());    
  }   
});

除非配合HTTPS,否则这不是一种安全的验证机制。特别是,用户名,密码,请求和响应都没有经过加密就进行网络传输。

带Cookies的Sessions

建立和保持一个在服务器和客户端之间长期存活的session,HttpURLConnection包含一个可以扩张的cookie管理器。允许VM-wide cookie管理者用CookieHandlerCookieManager

CookieManager cookieManager = new CookieManager();   
CookieHandler.setDefault(cookieManager);

默认的,CookieManager只从原始服务器接收cookies。除此之外还有另外两个策略:ACCEPT_ALLACCEPT_NONE.实现CookiePolicy来定义一个自己的策略。

默认的CookieManager把所有接收的cookie保存在内存中。当VM退出时,它能够忘记这些cookies.实现CookieStore来定义一个自己的cookie store.

除此之外,依靠HTTP响应来设置cookies,你能用编程的方式设置cookies。为了包含在HTTP请求头中,cookies必须有域名和路径所有权

默认的,新的HttpCookie实例只在支持RFC 2965 cookies的服务器上工作。许多web服务器只支持老的规格,RFC 2109.为了兼容大多数web服务器,设置cookie版本为0.

举个例子:

   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)

IP6的支持

这个类包含了对IP6的传输支持。对于包含IP4和IP6地址的主机,一旦建立连接,它会试图连接每一个主机的地址。

响应缓存

Android 4.0 (Ice Cream Sandwich, API level 15)以上包含了响应缓存。看android.net.http.HttpResponseCache的用法说明,来在你的应用当中使用HTTP缓存。

避免旧版本中的bug

在Android 2.2以前,对一个可读的InputStream调用close()方法时,就有可能会导致连接池失效了。我们通常的是直接禁用掉连接池来解决这个问题:

   private void disableConnectionReuseIfNecessary() {
   // Work around pre-Froyo bugs in HTTP connection reuse.
   if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) {
     System.setProperty("http.keepAlive", "false");
   }
 }

每个HttpURLConnection实例都可以用于一个请求/响应对。 这个类的实例不是线程安全的。

文/鬼谷阳明(简书作者)

原文链接:http://www.jianshu.com/p/c03216153876X132X

Copyright© 2020-2022 li-xyz 冀ICP备2022001112号-1