Denua 博客

OkHttp 总结, 常见问题以及简单封装

发布时间: 2018-10-31 14:31   分类 : Android    标签: Android 网络请求 浏览: 48   


这篇文章总结了 OKHttp 的一些知识点, 以及使用过程中容易出现的问题, 我对 OKHttp 的封装. OKHttp 的特点: 使用简单方便, 设计非常巧妙, 使用了很多设计模式. 支持 https, 支持 websocket, 管理cookie 方便, 缓存机制, 拦截器. 文章结构 # 一. 简单使用 ## 1 构建一个 OKHttpClient 简单翻译即为 OKHttp 客户端, 在发送请求之前, 我们需要构建一个 OKHttpClient 对象, 该对象用于发送我们构建的请求, 并管理一些请求所需要的配置, 例如如何处理 Cookies, 统一 Headers, 如何配置 SSL/TSL 协议. 在一般情况下, 我们只在全局构建一个 OKHttpClient 对象, 因为这样我们不需要为每个请求都配置一些共有的参数. 构建该对象使用了构建者模式, OkHttp 中大量使用构建者模式以及其他一些设计模式. 这里我们构建了一个最简单的 client 对象. OKHttpClient client = new OkHttpClient.Builder().build(); ## 2 Request 类, 构建 HTTP 请求 OKHttp 将所有类型的请求都封装为一个 Request, 一个 Request 中主要的参数有 url, method, 请求参数, header, 支持的请求方法有 GET, HEAD, POST, DELETE, PUT, PATCH. 其中协议类型不能像浏览器一样省略. ### 2.1 构建 GET 请求 Request request = new Request.Builder().url("https://www.baidu.com").get().build(); 这里我们构建了一个请求, 请求 url 为百度首页, 方法为 get, 其中 get 方法可以省略, 默认方法就是 get. ### 2.2 构建 POST 请求 FormBody formBody = new FormBody.Builder() .add("name1", "value1") .add("name2", "value2") .addEncoded("name3",new String("value3".getBytes(), Charset.forName("utf-8"))) .build(); Request request = new Request.Builder() .url("http://example.com") .post(formBody) .build(); post 请求与 get 不同的是多了一个 FormBody 请求表单. 在一些特殊情况下可以用 addEncoded 对部分字段设置编码方式, 那么将不会再次对应字段进行编码. ## 3 发送请求 发送请求前需要先用之前创建的 client 以及 request 创建一个 call. Call 类似于在浏览器点击一个链接开启的一个新页面, 我们可以查看该页面的状态,是否请求完成, 或者关闭该页面取消这次请求. 这个步骤的意义在于我可以在他返回请求结果前取消他, 为什么要取消, 例如用户打开一个页面我们发起一个网络请求在结果没有返回之前用户又关闭了, 而请求结果返回到页面时页面已经销毁, 将引起一个 NullPointException. Call call = client.newCall(request); ### 3.1 同步请求 Response response = call.execute(); 调用 call 的 execute 方法即可执行该请求, 同步请求将阻塞当前线程, 在 Android 主线程中调用这个方法将引发 ANR(Application Not Response) 错误. 直到请求结果返回给 response. 所有的关于这次请求的内容都可以在该 response 中得到. ### 3.2 异步请求 call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) throws IOException { }); 调用 enqueue 方法并传入一个用于监听请求结果的 CallBack 接口实例即可异步执行该请求. CallBack 中 onFailure 表示服务器响应失败, 多半是网络问题, onResponse 表示收到服务器响应. ## 4 请求结果, Response 所有关于这次请求的内容, 都封装在这个对象中, 比如请求 Request, 响应 Header. 响应时长, 使用协议, 是否重定向, 等等. ### 4.1 响应主体 ResponseBody 在请求结果 response 中包含了我们需要的响应主体 responseBody, 在 responseBody 中我们可以获取更多我们直接想要的类型的结果, 比如 String, InputStream, bytes. 同时还可以通过该对象获取到响应主体的 MIME 类型, 响应主体大小. 其中应注意的是, string() 方法只能调用一次. ResponseBody responseBody = response.boody() responseBody.string(); responseBody.contentType(); responseBody.byteStream(); ### 4.2 Response 比较重要的几个方法 + isSuccessful() 请求是否返回 200 OK, 表示这次请求是否成功. + code() 响应 HTTP 状态码, 用于判断这次响应的状态. + headers() 包含了本次响应的所有 header. + request() 这个响应的请求对象 + close() 关闭响应流并释放系统资源 # 二. 如何管理 Cookies 以及 Headers Cookie 和 Header 是我们经常需要设置的, 而 OkHttp 对这方面提供的方法和接口非常方便使用. ## 1 Cookies cookie 的属性介绍 + name cookie 的名称 + value 值 + domain 该 cookie 的使用域名 + path 路径 + secure 是否只在使用 https 时传输该 cookie + expires/Max-Age 过期时间, 默认为直到浏览器关闭 在构建 OkHttpClient 对象的时候, 其中有一个 cookieJar 方法, 这个方法中接受一个 CookieJar 接口, 我们只需传入一个实现了该接口的对象即可. 从该接口方法名即可看出. saveFromResponse 方法即但响应中有 cookie 时调用, 用于保存从响应中返回的 cookie. 而 loadForRequest 则是每次请求都将调用, 我们可以根据传入的 url 返回相应的 cookie. 这里我实现了一个简单管理 cookie 的 CookieManager. OkHttpClient client = new OkHttpClient.Builder() .cookieJar(new CookieManager()) .build(); ... class CookieManager implements CookieJar{ private Map#String, ConcurrentHashMap#String, Cookie## cookies = new HashMap()(); @Override public void saveFromResponse(@NonNull HttpUrl httpUrl, @NonNull List#Cookie# list) { if (list.size() # 0) { for (Cookie item : list) { add(httpUrl, item); } } } @Override public List#Cookie# loadForRequest(@NonNull HttpUrl url) { ArrayList#Cookie# ret = new ArrayList##(); if (cookies.containsKey(url.host())) ret.addAll(cookies.get(url.host()).values()); return ret; } private void add(HttpUrl url, Cookie cookie){ String name = cookie.name() + "@" + cookie.domain(); if (cookie.persistent()) { if (!cookies.containsKey(url.host())) { cookies.put(url.host(), new ConcurrentHashMap##()); } cookies.get(url.host()).put(name, cookie); } else { if (cookies.containsKey(url.host())) { cookies.get(url.host()).remove(name); } } } } 我在这里遇到一个问题, 在 saveFromResponse 中的 cookie 如果没有设置 expired 属性, cookie 的过期时间值则 persistent 会为 false, expiredAt() 返回一个错误的时间. 在这一点需要注意一下. ## 2. Headers 比较低级的方法就是直接给 Request 设置 headers, 比较好的方法是在构建 OkHttpClient 对象时通过 addInterceptor 方法添加一个拦截器给所有请求添加header. 拦截器将在后面介绍, 这里先用第一种方法. Headers headers = new Headers.Builder() .add("User-Agent","okhttpclient") .add("Host","baidu.com") .build(); Request request = new Request.Builder().url("https://baidu.com").headers(headers).build(); 非常简单.但是如果每个请求都要这样设置就不简单了. # 三. Multipart 类型表单, 上传文件 # 四. Interceptor, 拦截器 # 五. 使用 HTTPS, 设置 X509TrustManager 和 HostNameVerifier # 六. 简单的封装 有待更新

评论    

udceoh [2018-11-10 09:53] : <a href=http://canadian-pharmacyn.com>buy cialis 20mg</a> generic cialis 20mg online http://canadian-pharmacyn.com <a href=http://canadian-pharmacyn.com>cialis samples online</a>

Copyright denua denua.cn