尽管现在项目中已经普遍采用okhttp等框架进行网络请求,但出于开发的高性能要求,我们仍有必要对一些网络请求的性能要点进行讨论,以便对网络请求中的整体编码和第三方框架的配置使用有更深入的认识。
5.1 网络请求编码的基本要素
当我们开始讨论网络请求时,从客户端的角度来说,主要涉及三个方面:客户端、请求、响应。从开发编码的角度来说,我们主要会关注请求和响应的几个具体要素,如下图所示。
为了处理这些请求和响应要素,Android原生为我们提供了两个主要的Api家族:
l HttpClient : The DefaultHttpClient and AndroidHttpClient classes are the main classes to use for this HTTPimplementation.
l URLConnection : This is a more flexible and performant API toconnect to a URL. It can use different protocols.
但是,Android官方不再推荐HttpClient并从API Level 23开始将其移除SDK,尽管有一些第三方库还可以提供支持,但考虑到SDK的后续更新方向,强烈要求不再使用。
因此,如果使用原生网络请求接口的话,要求只能使用URLConnection家族,而这也是众多网络开源框架的趋势。
5.2 关于HttpURLConnection
URLConnection是所有表示应用程序与URL之间通信连接的类的父类(superclass),该类的实例可以用来对由URL引用的资源进行读取和写入操作。
HttpURLConnection 是支持HTTP特定功能的URLConnection,还有JarConnection是URLConnection的直接子类。
众多开源框架基于URLConnection提供了良好的编码接口,也不排除在某些场景,我们采用该API自定义轻量级的网络请求封装,本小节将简介URLConnection本身的一些基本用法。
5.2.1 Protocols
当我们讨论网络通信的时候,我们比较感兴趣的是使用HTTP协议来执行网络数据通信,但是使用URLConnection及其子类可以支持数据协议包括:
l HTTP and HTTPS:HttpUrlConnection是本家族的主要类,用于执行http请求;
l FTP:默认的URLConnection类提供了FTP通信接口,使用其即可执行FTP通信;
l File:本地文件系统也可以使用URLConnection基于URI进行访问;
l JAR:这种协议用来处理JAR文件,可以使用JarUrlConnection扩展类来执行。
5.2.2 Methods
HttpURLConnection类提供的主要请求方式为:
l GET:这是默认的请求方式,不需要做特别的设置即可使用;
l POST:通过调用URLConnection.setDoInput()接口,即可实现Post请求;
其它请求方式,可以通过调用URLConnection.setRequestMethod()方法来实现
5.2.3 Headers
当准备发送请求时,我们可能有必要增加一些metadata数据,或者增加一些用户和session信息等等,来让服务器指导客户端的的相关状态。头信息Headers将以key/value的格式承载这些信息,并且也可以在响应的时候,读取服务端修改的一些信息,比如响应数据的格式、启用压缩等。
头信息的使用主要涉及两个接口:
l URLConnection.setRequestProperty()
l URLConnection.getHeaderFields()
5.2.4 Timeout
URLConnection支持两种类型的超时:
l 连接超时Connect timeout:通过调用URLConnection.setConnectTimeout()方法设置超时时间,在期间内,客户端将等待连接成功;如果连接超时,将抛出SocketTimeoutException异常;
l 读取超时Read timeout:通过调用URLConnection.setReadTimeout()方法设置,这是Inputstream读完的时间限制,如果读取超时,也将抛出SocketTimeoutException异常。
两者的默认值都是0,即没有超时设置。因此,默认的超时机制将由TCP传输层自行进行控制,这个时间通常较长,超出我们的可控范围。
5.2.5 Content
当我们和服务端启动一个新的connection后,即开始等待响应,通过调用URLConnection.getContent()方法,将以InputStream的方式获取到响应内容;同时还有几个响应参数以及三个主要的头信息:
l Content length:响应内容的长度,通过调用URLConnection.getContentLength()方法进行读取;
l Content type:响应内容的MIME-type通过调用URLConnection.getContentType()读取;
l Content encoding:压缩编码方式,通过调用URLConnection.getContentEncoding()方法读取。
5.2.6 Compression
通过上述Content encoding读取的值,将知道响应内容的压缩方式,当然客户端也可以通过设置Accept-Encoding头字段来告知服务端其期望的方式。
服务端默认不启用压缩,但是客户端应该通过URLConnection.getContentEncoding()方法检查返回的结果;客户端不会自动解压,如果数据流是压缩的话,需要使用GZIPInputStream方式代替默认的InputStream流来读取数据。
5.2.7 Response code
响应返回码将决定客户端不同的处理方式,通过调用HttpURLConnection.getResponseCode()方法获取code之后,执行不同的响应。响应码通常包含如下几组:
2xx:成功,服务端接收到请求并发送返回数据;
3xx:重定向,大多数情况下由http层自动完成,不需要额外处理;其中304属于服务端无更新;
4xx:客户端请求出错,可能是请求的参数或语法有误,资源无法找到等;
5xx:服务端响应失败,服务器内部出错或者负载过重。
5.3 区分网络条件
客户端可以根据网络连接状态决定如何执行请求,以及请求什么样的数据,无论使用上述HttpURLConnect接口还是第三方网络请求库,都应当进行不同的处理,至少包括不同的请求超时和不同的数据响应。
5.3.1 Connection types
通过调用ConnectionManager.getActiveNetworkInfo()来获得NetworkInfo,通过NetworkInfo.getType()获取具体的网络连接类型,通常有以下几种:
l TYPE_MOBILE
n TelephonyManager.NETWORK_TYPE_LTE
n TelephonyManager.NETWORK_TYPE_GPRS
l TYPE_WIFI
l TYPE_WIMAX 即全球微波互联接入,美国Sprint