Okhttp是现在非常流行的网络框架,据说是可以取代我们自己手码java.net.*或Org.apache的强大工具,那么它到底有何优势呢?在其官网上有如下描述:
OkHttp是一个高效的HTTP客户端:
1 HTTP2支持允许所有有相同host的请求分享一个socket。
2 连接池降低了请求延时(如果http2无效)
3 GZIP压缩了下载大小
4 缓存Response,完全避免了网络重复请求。
当网络出问题的时候,OkHttp依然会屹立不倒:它会从常见的连接问题中悄悄恢复。如果你的服务有多个IP地址,它将会在第一个地址连接失败之后尝试连接其他几个可选地址,这对于IPv4+IPv6的情况以及服务运行在多个备份数据中心的情况尤其重要。它支持TLS(与SSL同级类似)的新特性(SNI,ALPN),如果握手失败它会退回到TLS1.0。
OkHttp的使用非常简单,它的request和response API使用了builder和非可变性来设计。它既支持同步阻塞也支持异步回调。
OkHttp支持android2.3及以上,java最低要求1.7。
要了解这些优点需要对http协议有一些认识:
1 相同host的请求分享一个socket是什么意思?
在网络层有IP协议、ICMP协议、ARP协议、RARP协议和BOOTP协议。
在传输层中有TCP协议与UDP协议。
在应用层有:TCP包括FTP、HTTP、TELNET、SMTP等协议;UDP包括DNS、TFTP等协议。
这三层从底到高依次是网络层,传输层,应用层。那么socket就是封装了传输层的复杂操作提供给应用层的接口,无论应用层怎么玩,玩的基本对象就是它,常听说短连接长连接其实都是针对socket要不要保持这次请求不断,而FTP、HTTP等都是建立在TCP协议之上的协议,相当于FTP协议规定一种socket的一套玩法、HTTP协议规定了另一种socket的一套玩法。长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况。每个TCP连接都需要三步握手,这需要时间,如果每个操作都是先连接,再操作的话那么处理速度会降低很多,所以每个操作完后都不断开,次处理时直接发送数据包就OK了,不用建立TCP连接。例如:数据库的连接用长连接, 如果用短连接频繁的通信会造成socket错误,而且频繁的socket 创建也是对资源的浪费。而像WEB网站的http服务一般都用短链接,因为长连接对于服务端来说会耗费一定的资源,而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源,如果用长连接,而且同时有成千上万的用户,如果每个用户都占用一个连接的话,那可想而知吧。所以并发量大,但每个用户无需频繁操作情况下需用短连好。
那么回到问题上来,无论什么协议,如果要发起一次请求,那么需要创建socket再进行握手等等,握手成功才开始传输数据。对于HTTP协议来说,每一次发起请求,都需要重新走一遍这个初始化流程,比如说加载一个网页,只要获取数据展示出来就可以满足用户的需求了,这时我们就应当关闭这个通道,让用户自己玩去;但如果加载这个页面需要发起许多个请求才能完成加载呢,比如需要获取多个js和css文件数据,这时就会出现有多少个请求就得走多少遍初始化流程。那么相同host的请求分享一个socket,也就意味着这些初始化流程只需要走一次。知乎上有人提出如果这里设置keep-alive使用长连接不是一样的效果吗?后来有高人贴了一张图:
这就是它的强大之处,它可以合并请求。而这个优点归功于HTTP2协议,继承了其前身SPDY协议的优良基因。
2 什么是GZIP压缩
实际上我们并不需要去了解什么是GZIP压缩,只需要知道它对传输的数据进行了压缩,那么传输效率肯定就增加了,但本着了解的心态查阅了一下,其压缩方式还是比较独特的。其原理是对一个文件先进行ZL77算法压缩,再进行Huffman编码压缩。ZL77即是在一段数据里依次找到多处相同的数据块,保留第一块的内容,用索引和大小来替换后面相同数据块的内容。而Huffman编码还没有理解透。
3 其基本用法在其官网上也可以看到:
package okhttp3.guide; import java.io.IOException; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; public class GetExample { OkHttpClient client = new OkHttpClient(); String run(String url) throws IOException { Request request = new Request.Builder() .url(url) .build(); Response response = client.newCall(request).execute(); return response.body().string(); } public static void main(String[] args) throws IOException { GetExample example = new GetExample(); String response = example.run("https://raw.github.com/square/okhttp/master/README.md"); System.out.println(response); } }
package okhttp3.guide; import java.io.IOException; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; public class PostExample { public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); OkHttpClient client = new OkHttpClient(); String post(String url, String json) throws IOException { RequestBody body = RequestBody.create(JSON, json); Request request = new Request.Builder() .url(url) .post(body) .build(); Response response = client.newCall(request).execute(); return response.body().string(); } String bowlingJson(String player1, String player2) { return "{'winCondition':'HIGH_SCORE'," + "'name':'Bowling'," + "'round':4," + "'lastSaved':1367702411696," + "'dateStarted':1367702378785," + "'players':[" + "{'name':'" + player1 + "','history':[10,8,6,7,8],'color':-13388315,'total':39}," + "{'name':'" + player2 + "','history':[6,10,5,10,10],'color':-48060,'total':41}" + "]}"; } public static void main(String[] args) throws IOException { PostExample example = new PostExample(); String json = example.bowlingJson("Jesse", "Jake"); String response = example.post("http://www.roundsapp.com/post", json); System.out.println(response); } }