一.OkHttp的介绍
概述
• okhttp是一个第三方类库,用于Android中请求网络
• 这是一个开源项目,是安卓端最火热的轻量级框架,由移动支付Square公司贡献(该公司还贡献了Picasso和LeakCanary) 。用于替代HttpUrlConnection和Apache HttpClient(android API23 里已移除HttpClient)。
• 官网地址:OkHttp官网
• git地址:https://github.com/square/okhttp
OkHttp与http请求
我们先构造一个http请求,并查看其具体内容
在上一篇博客里我们曾说过,http协议请求消息体 分为4部分请求行、请求头部、空行和请求数据,其中请求行又包含请求方法,请求地址,请求协议。
所以说个类库要完成一个http请求, 需要包含 请求方法, 请求地址, 请求协议, 请求头, 请求体这五部分,这些在 这些都在okhttp3.Request的类中有体现, 这个类正是代表http请求的类。
为什么没有请求协议,因为在http中引入了Upgrade 机制.。简单来说就是根据服务器支持那种协议(Http/1.1 Http/2),就选择那种协议。
3.OkHttp与http响应
使用Okhttp保存表示一个响应
在上一篇博客中,我们提过其分为四个部分状态行、消息报头、空行和响应正文,状态行又包含访问协议,响应码,描述状态的信息, 所以来说响应应包括访问协议, 响应码, 描述信息, 响应头, 响应体。
在okhttp中的Response中:
二.Get请求
1.同步GET
同步GET的意思是一直等待http请求, 直到返回了响应. 在这之间会阻塞进程, 所以通过get不能在Android的主线程中执行, 否则会报错。
运行结果
注意事项:
• Response.code是http响应行中的code,如果访问成功则返回200,这个不是服务器中设置的,而是http协议中自带的,res中的code才是服务器设置的。
•response.body().string()本质是输入流的读操作,所以它还是网络请求的一部分,所以这行代码也必须放在子线程中。
•response.body().string()只能调用一次,在第一次是有返回值,第二次调用就会返回null。原因:response.body().string()的本质是输入流的读操作,必须有服务器的输出流的写操作时客户端的读操作才能得到数据。而服务器的写操作只执行一次,所以客户端的读操作也只能执行一次,第二次将返回null。
2.异步GET
异步GET是指在另外的工作线程中执行http请求,请求时不会阻塞当前的线程,所以可以在Android主线程中使用。
异步请求的打印结果和注意事项和同步请求时相同,最大的不同就是异步请求不需要开启子线程,enqueue方法会自动将网络请求部分放在子线程中执行。
注意事项:
•回调接口onFailure和onResponse执行在子线程。
•response.body().string()方法也必须放在子线程中。当执行这行代码得到结果后,再跳转到UI线程修改UI。
三.POST请求
1. Post方式提交String
下面使用POST提交到服务中,这里的例子是提交一个markDown文件到web服务,以html方式渲染markdown。
运行结果:
2. POST方式提交流
以流的方式POST提交请求体,请求体的内容由流写入产生,这个例子是流直接写入OKio的BufferedSink。 你的程序可能会使用OutputStream,你可以使用BUfferedSink.outputStream()来获取,OkHttp的低层对流和字节的操作都是基于Okio库,Okio库也是Square开发的另一个IO库,填补I/O和NIO的空缺目的提供简单便于使用的接口来操作I/O。
运行结果:
3.POST方式提交文件
以文件为请求体是比较简单的
运行结果:
4.Post方式提交表单
使用FormEncodingBuilder来构建和HTML标签相同效果的请求体. 键值对将使用一种HTML兼容形式的URL编码来进行编码。
运行结果:
5.Post方式提交分块请求
MultipartBody.Builder可以构建复杂的请求体,与HTML文件上传形式兼容,多块请求体中每块请求都是一个请求体,可以定义自己的请求头,这些请求头可以用来描述这块请求,例如它的Content-Disposition. 如果Content-Length和Content-Type可用的话, 他们会被自动添加到请求头中。
四.缓存响应
• OKhttp中关于缓存的详细内容:可以看这一篇博客OKHTTP之缓存配置详解
• okHttp中缓存整体上来说主要在两个地方配置,一个是构造OKHttpClient时,还有一个是在构造Request时,一共就这两次,让我们分别来看。
1.在OkHttpClient构造时设置缓存路径
在使用OkHttp时,一般都会讲client的获取封装起来,因为在大多数的情况下,我们需要的OkHttpClien是一样,在封装的时候,就可以设置许多属性,其中就包括cache,配置cache后,OkHttp请求的数据就会缓存到该路径下,当手机没有联网时,就可以直接从缓存中获取。
第一次访问的结果:
第二次访问结果:
第一次访问的时候,Response的消息是NetworkResponse消息,此时CacheResponse的值为Null。而第二次访问的时候Response是CahceResponse,而此时NetworkResponse为空。也就说明了上面的示例代码能够进行网络请求的缓存。
2.构造Request时配置缓存策略
在构造Request的时候,我们可以配置CacheControl,配置有两种方式,一种是构造CacheControl,还有一种是直接使用CacheControl中的常量,我们来分别看一下:
a. 构造CacheControl
b.使用CacheControl中的常量
如果直接使用CacheControl中的常量,则不用调用上面那么多的方法,使用方式如下:
五.OkHttp的其他用法
1.提取响应头
典型的HTTP头是一个Map : 每个字段都有一个或没有值. 但是一些头允许多个值, 像Guava的Multimap。例如:HTTP响应里面提供Vary响应头,就是多值的,okhttp试图让这些情况都适用。
当写请求头的时候,使用header(name,value)可以设置唯一的name,value.如果已经有值,旧的值将被溢出,然后添加新的,使用addHeader(name,value)可以添加多值(添加,不移除已有的)。
当读取响应头时,使用header(name)返回最后出现的name、value. 通常情况这也是唯一的name、value. 如果没有值, 那么header(name)将返回null. 如果想读取字段对应的所有值, 使用headers(name)会返回一个list。为了获取所有的Header, Headers类支持按index访问。
2.取消一个Call
使用Call.cancel可以理解停止一个正在执行的call,如果一个线程正在请求或者读响应,引发IOException,当没有必要的时候,这个api可以节约网络资源,例如当用户离开一个应用时,不管是同步还是异步都可以取消。
你可以通过tags来同时取消多个请求. 当你构建一请求时, 使用RequestBuilder.tag(tag)来分配一个标签, 之后你就可以用OkHttpClient.cancel(tag)来取消所有带有这个tag的call。
取消成功:
3.超时
没有响应时使用超时结束call. 没有响应的原因可能是客户点链接问题、服务器可用性问题或者这之间的其他东西.。OkHttp支持连接超时, 读取超时和写入超时。
4.处理验证
这部分和HTTP AUTH有关:HTTP AUTH是一种基础的用户验证,原理是将用户名:密码base64加密后放在http的请求头部Authorization 发给服务器 。
a.HTTP AUTH
使用HTTP AUTH需要在server端配置http auth信息, 其过程如下:
•客户端发送http请求。
• 服务器发现配置了http auth,于是检查面有没有"Authorization"的http header。
• 如果有,则判断Authorization里面的内容是否在用户列表,Authorization header的典型数为"Authorization: Basic jdhaHY0=", 其中Basic表示基础认证, jdhaHY0=是base64编码的"user:passwd"字符串. 如果没有,或者用户密码不对,则返回http code 401页面给客户端。
• 标准的http浏览器在收到401页面后,应该弹出一个对话框让用户输入账号密码,并在用户点确认的时候再次发出请求, 这次请求里面将带上Authorization header。
一次典型的访问场景
• 浏览器发送http请求(没有Authorization header)
• 服务器端返回401页面
• 浏览器弹出认证对话框
• 用户输入账户密码,并点确认
• 浏览器再次发出http请求(带着Authorization header)
• 服务器端认证通过,并返回页面
• 浏览器显示页面
b.OkHttp认证
OkHttp会自动重试未验证的请求,当响应的是401 Not Authorized时,Authenticator会被要求提供证书.。Authenticator的实现中需要建立一个新的包含证书的请求. 如果没有证书可用, 返回null来跳过尝试。
使用Response.challenges()来获得任何authentication challenges的 schemes 和 realms.。当完成一个Basic challenge, 使用Credentials.basic(username, password)来解码请求头。
当认证无法工作时, 为了避免多次重试, 你可以返回空来放弃认证。 例如, 当exact credentials已经尝试过, 你可能会直接想跳过认证, 可以这样做:
当重试次数超过定义的次数, 你若想跳过认证, 可以这样做:
六.参考资料
• OkHttp使用完全教程
• OkHttp用法
• OKHTTP之缓存配置详解
• HTTP AUTH验证
微信:西邮3g实验室
微博:西邮移动应用开发实验室
西邮3G实验室
本期作者:Android组和书诚
领取专属 10元无门槛券
私享最新 技术干货