现在每篇文章前都会吐槽下自己的生活事情,也当作个记录,本来想写这篇博客很久的了,看标题就知道,想 11 月 7 日就开始写的了,可是现在(2016年11月27日22:45:12)还没写完,因为这段事件赶公司的即时聊天的项目,还有每个星期都会来一篇算法的文章或做算法的题,因此导致这篇文章很久还没写完,不想拖下去,赶紧写完。
一、 OKHttp基础
我们可以通过右键 new——》Module——》java Library 的方式来创建一个 Module 的方式来测试一下 OKHttp3 ,为什么是创建 java Library 呢?因为对于一般的网络框架而已,我们只需要创建 java Library就可以了,不必要创建 Android Library 。
然后导入我们的OKHttp3,具体的官网在之前的系列文章中就有个介绍:
CSDN:http://blog.csdn.net/Two_Water/article/details/53055524
简书://www.greatytc.com/p/049a91e9958a
1.同步请求和异步请求
创建完项目后,来了解一下OKHttp3的同步请求和异步请求,虽然官网就有很详细的例子,可是最好还是自己读尝试一次,就算是跟着官网的例子敲一遍,还是有一番体会的。
package com.liangdianshui.http.lib;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
/**
* OKHttp 同步请求和异步请求
*
* Created by liangdianshui on 2016/11/8
*/
public class SendRequest {
/**
* 同步请求
* <p>
* 会阻塞当前线程
* </p>
*
* @param url
*/
public static void sendRequest(String url) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
try {
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
System.out.println(response.body().string());
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 异步请求
*
* @param url
*/
public static void sendAsyncRequest(String url) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
System.out.println(Thread.currentThread().getId());
}
}
});
}
public static void main(String args[]) {
sendRequest("http://blog.csdn.net/two_water");
System.out.println("-------------------------------------------");
System.out.println(Thread.currentThread().getId());
sendAsyncRequest("http://blog.csdn.net/two_water");
}
}
2.请求头和响应头
在上一个博客中也有介绍到响应头和请求头,也介绍了一大堆参数,那么我们如何使用这些参数呢?
package com.liangdianshui.http.lib;
import java.io.IOException;
import okhttp3.Headers;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
/**
* 增加请求头的请求
* Created by liangdianshui on 2016/11/8
*/
public class AddHeaderRequest {
public static void addHeaderRequest(String url) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(url)
.addHeader("User-Agent", "liangdianshui")
.build();
try {
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
Headers requestHeaders = request.headers();
System.out.println("----------Request Headers------------");
for (int i = 0; i < requestHeaders.size(); i++) {
System.out.println(requestHeaders.name(i) + " : " + requestHeaders.value(i));
}
Headers responseHeaders = response.headers();
System.out.println("------------Response Headers-----------");
for (int i = 0; i < responseHeaders.size(); i++) {
System.out.println(responseHeaders.name(i) + " : " + responseHeaders.value(i));
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
addHeaderRequest("http://blog.csdn.net/two_water");
}
}
我们也可以通过 Fiddler 来查看到我们请求中的请求头的,合理使用这些工具可以验证我们获取的数据是否正确,少走一些弯路
3.添加请求参数的get请求
请求参数的 get 请求,我们使用和风网的免费天气查询 api 作为例子,和风网的官网地址:
我们首先的注册一个用户,就会分配key:
注册完成后我们就可以去查找相关的API文档,看看如何调用:
最后就是上代码了:
package com.liangdianshui.http.lib;
import java.io.IOException;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
/**
* 添加请求参数的get请求
* <p>
* Created by Administrator on 2016/11/16 0016.
*/
public class AddQueryParameterRequest {
/**
* 使用和风网的免费天气查询的api
*/
public static void addQueryParameterRequest() {
OkHttpClient client=new OkHttpClient();
HttpUrl httpUrl=HttpUrl.parse("https://free-api.heweather.com/v5/now")
.newBuilder()
.addQueryParameter("city","shenzhen")
.addQueryParameter("key"," 9b82700caecd4d3aa709c54a7593754d")
.build();
Request request=new Request.Builder().url(httpUrl.toString()).build();
try {
Response response=client.newCall(request).execute();
if (response.isSuccessful()) {
System.out.println(response.body().string());
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
addQueryParameterRequest();
}
}
4.post请求
如果使用公共的 api 提交 post 请求,相对于 get 请求来说,是相对麻烦一些的,因此我们自己写一个简单的服务,来请求 post 请求,
服务器的代码主要是这个:
客户端代码:
package com.liangdianshui.http.lib;
import java.io.IOException;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
/**
* Created by liangdianshui on 2016/11/27 0027.
*/
public class PostRequest {
public static void postRequest(String url, String name, String password) {
OkHttpClient client = new OkHttpClient();
FormBody body = new FormBody.Builder().add("username", name).add("password", password).build();
Request request = new Request.Builder().url(url).post(body).build();
try {
Response reponse = client.newCall(request).execute();
if (reponse.isSuccessful()) {
System.out.println(reponse.body().string());
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
postRequest("http://localhost:8080/OKHttpTest/OKHttpPost", "liangdianshui", "123456");
}
}
运行的结果:
在这里呢,我们先了解一个知识点:
可以看到 post 请求中默认的类型就是:application/x-www-form-urlencoded 因此我们可以查看下我们 OKHttp 中的 FormBody 中的源码:
可以看到我们使用的 FormBody 就是这个类型的,而 multipart/form-data 这个类型主要是用于上传文件等相关操作的。因为这个上传方式不做编码处理,你上传什么就是什么
5.上传文件
这里我们先写一下服务器的代码,也要了解一下到底 http 是怎样上传文件的
先写一个 html 的页面:
然后我们看下服务器的代码,写的非常的简单,主要是我们只是了解下上传文件的流程而已。
我们来看下效果:
好了,服务器完成了,我们来查看一下上传文件的协议是怎样的:
可以看到,如果我们自己写上传文件的代码还是比较复杂的,只不过这里面的过程,OKHttp 都帮我们封装好了,因此使用起来还是比较简单的。
package com.liangdianshui.http.lib;
import java.io.File;
import java.io.IOException;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
/**
* Created by liangdianshui on 2016/11/28 0028.
*/
public class MultiparHttp {
public static void main(String args[]) {
//上传一张本地的图片
RequestBody imageBody = RequestBody.create(MediaType.parse("image/jpeg"), new File("C:\\Users\\Administrator\\Desktop\\service\\liangdianshui.jpg"));
MultipartBody body = new MultipartBody.Builder().
setType(MultipartBody.FORM). //要配置上传的类型,否则会上传不成功
addFormDataPart("name", "nate").
addFormDataPart("filename", "girl.jpg", imageBody).build();
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().
url("http://localhost:8080/OKHttpTest/UploadServlet").post(body).build();
try {
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
System.out.println(response.body().string());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行的结果:
6. Http 缓存
其实 OkHttp 给我们封装好了 Http 的缓存,用起来还是挺方便的,可是我们不能仅限于在用,先不说我们要创造属于自己的艺术品,起码我们得知其所以然,只有这样,才能有利于我们技术的进阶。竟然说到 Http 的缓存,那么我们必需得问,为什么要有 Http 请求缓存呢?每个设计肯定有它的思想所在,我们得理解,得探讨。
为什么要有 Http 请求的缓存?
(1)快: 缓存缓解了网络瓶颈的问题,不需要更多的网络带宽就能更快的加载页面。
(2)省:缓存减少了冗余的数据传输,节省了网络费用。
(3)低:缓存降低了对原始服务器的要求,服务器可以更快的响应。同时,搜索引擎的爬虫机器人也能根据过期机制降低爬取的频率,也能有效降低服务器的压力。
当然 Http 请求缓存给我们带来了一系列的好处之外,也有它的不足,那么它有什么不足或缺点呢?
(1)占空间:缓存没有清理机制,这些缓存的文件会永久性地保存在机器上,在特定的时间内,这些文件可能是帮了你大忙,但是时间一长,我们已经不再需要浏览之前的这些网页,这些文件就成了无效或者无用的文件,它们存储在用户硬盘中只会占用空间而没有任何用处,如果要缓存的东西非常多,那就会撑暴整个硬盘空间。
(2)不即现:因为缓存,有时候我们明明修改了样式文件、图片、视频或脚本,刷新页面或部署到站点之后看不到修改之后的效果。所以在产品开发的时候我们总是想办法避免缓存产生,而在产品发布之时又在想策略管理缓存提升网页的访问速度。这就给我们带来了一定的困扰。
那么是怎样实现 Http 的缓存的呢?
其实 Http 缓存在不同的类型上缓存的方式不一样,可是原理还是一样的,我们通过了解浏览器缓存来探讨一下是怎样实现的?
Http 请求缓存中相关的字段有哪些呢?
最后通过请求我的博客来看一下缓存:
其中:
Cache-control 常见的取值有 private、no-cache、max-age、must-revalidate 等,默认为private 。其作用根据不同的重新浏览方式分为以下几种情况:
(1) 打开新窗口
如果指定 cache-control 的值为 private、no-cache、must-revalidate,那么打开新窗口访问时都会重新访问服务器。而如果指定了 max-age 值,那么在此值内的时间里就不会重新访问服务器,例如:
Cache-control: max-age=5
表示当访问此网页后的5秒内再次访问不会去服务器
(2) 在地址栏回车
如果值为 private 或 must-revalidate(和网上说的不一样),则只有第一次访问时会访问服务器,以后就不再访问。如果值为 no-cache,那么每次都会访问。如果值为 max-age ,则在过期之前不会重复访问。
(3) 按后退按扭
如果值为 private、must-revalidate、max-age,则不会重访问,而如果为 no-cache,则每次都重复访问
(4) 按刷新按扭
无论为何值,都会重复访问
最后我们来看下 OKHttp 是如何设置缓存的:
/**
* 请求一个网址,设置缓存
* <p>要进行缓存,首先网址的服务器端先要支持缓存,再者,我们可以通过
* @code:{ public Builder cacheControl(CacheControl cacheControl) } 的方式控制客户端的缓存</p>
*
* @param url
* @param file
* @param maxCacheSize
* @throws IOException
*/
public static void cachRequest(String url, File file, int maxCacheSize) throws IOException {
Cache cache = new Cache(file, maxCacheSize);
OkHttpClient client = new OkHttpClient.Builder().cache(cache).build();
Request request = new Request.Builder().url(url).build();
Response response = client.newCall(request).execute();
String body = response.body().string();
}
想了解 OKHttp 是如何实现缓存的,我们可以先从 OKHttp 整个的流程图中入手:
本来还想写完缓存的分析的,可是看了下时间(2016年11月29日01:25:49)已经很晚了,还是睡了,明天还得上班,其实 OKHttp 缓存的实现看了很久源码,里面一大堆的 if 判断,看的有点晕,不过整体大概的原理还是可以理解的,细节的部分就略过了。哎,总是对自己那么仁慈,可能这就是跟大神的距离了。