1.什么是OkHttp
github地址:https://square.github.io/okhttp/
由Square公司贡献的一个处理网络请求的开源项目,是目前Android使用最广泛的网络框架。从Android4.4开始
HttpURLConnection的底层实现采用的是OkHttp。
1.支持HTTP/2并允许对同一主机的所有请求共享一个套接字;
2.如果非HTTP/2,则通过连接池,减少了请求延迟;
3.默认请求GZip压缩数据;
4.响应缓存,避免了重复请求的网络;
依赖:
implementation(“com.squareup.okhttp3:okhttp:4.9.0”)
测试(用于测试http请求的服务器):
URL:https://www.httpbin.org/
2.OkHttp基本用法
OkHttpClient okHttpClient = new OkHttpClient();
同步请求:
Request request = new Request.Builder().url("https://www.httpbin.org/get?a=1&b=2").build();
// 准备好请求的Call对象
Call call = okHttpClient.newCall(request);
try {
Response response = call.execute();
Log.i(TAG, "getSync: " + response.body().string());
} catch (IOException e) {
e.printStackTrace();
FormBody formBody = new FormBody.Builder()
.add("a", "1").add("b", "2").build();
Request request = new Request.Builder().url("https://www.httpbin.org/post")
.post(formBody).build();
// 准备好请求的Call对象
Call call = okHttpClient.newCall(request);
try {
Response response = call.execute();
Log.i(TAG, "postSync: " + response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
异步请求:
Request request = new Request.Builder().url("https://www.httpbin.org/get?a=1&b=2")
.build();
// 准备好请求的Call对象
Call call = okHttpClient.newCall(request);
//异步请求
call.enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
if (response.isSuccessful()) {
Log.i(TAG, "getAsync: " + response.body().string());
}
}
FormBody formBody = new FormBody.Builder()
.add("a", "1").add("b", "2").build();
Request request = new Request.Builder().url("https://www.httpbin.org/post")
.post(formBody).build();
// 准备好请求的Call对象
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
Log.i(TAG, "postAsync: " + response.body().string());
}
3.POST请求
协议规定 POST 提交的数据必须放在请求体中,但协议并没有规定数据必须使用什么编码方式 。而常用的数据编 码方式有:
https://www.runoob.com/http/http-content-type.html
1.Content-Type:application/x-www-form-urlencoded 数据被编码为名称/值对,默认类型;
2.Content-Type:multipart/form-data 数据被编码为一条消息,一般用于文件上传;
3.Content-Type:application/octet-stream 提交二进制数据,如果用于文件上传,只能上传一个文件;
4.Content-Type:application/json 提交json数据
…
multipart上传文件示例(创建测试代码,上传本地桌面文档):
@Test
public void uploadFileTest() throws IOException {
OkHttpClient okHttpClient = new OkHttpClient();
File file1 = new File("C:\\Users\\Administrator\\Desktop\\1.txt");
File file2 = new File("C:\\Users\\Administrator\\Desktop\\2.txt");
MultipartBody multipartBody = new MultipartBody.Builder()
.addFormDataPart("file1", file1.getName(), RequestBody.create(file1, MediaType.parse("text/plain")))
.addFormDataPart("file2", file2.getName(), RequestBody.create(file2, MediaType.parse("text/plain")))
.addFormDataPart("a", "1")
.build();
Request request = new Request.Builder().url("https://www.httpbin.org/post").post(multipartBody).build();
Call call = okHttpClient.newCall(request);
Response response = call.execute();
System.out.println(response.body().string());
}
json格式上传示例:
```java
@Test
public void jsonTest() throws IOException {
OkHttpClient okHttpClient = new OkHttpClient();
RequestBody requestBody =
RequestBody.create("{\"a\":1,\"b\":2}", MediaType.parse("application/json"));
Request request = new Request.Builder().url("https://www.httpbin.org/post").post(requestBody).build();
Call call = okHttpClient.newCall(request);
Response response = call.execute();
System.out.println(response.body().string());
}
4.Builder构建者
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
5.拦截器
OkHttpClientokHttpClient=newOkHttpClient.Builder().addInterceptor(newXXX).build();
OkHttpClientokHttpClient=newOkHttpClient.Builder().addNetworkInterceptor(newXXX).build();
6.缓存与Cookie
OkHttp按照Http协议规则实现了缓存的处理,缓存是比如:当我们发起第一次请求之后,如果后续还需要进
行同样的请求,此时如果符合缓存规则,则可以减少与服务器的网络通信,直接从本地文件缓存中读取响应
返回给请求者。但是默认情况下,OkHttp的缓存是关闭状态,需要我们开启。
拦截器以及缓存代码示例:
@Test
public void interceptorTest() {
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.cache(new Cache(new File("C:\\Users\\Administrator\\Desktop"),
1024 * 1024)).addNetworkInterceptor(new Interceptor() {
@NotNull
@Override
public Response intercept(@NotNull Chain chain) throws IOException {
System.out.println("version:" + chain.request().header("version"));
return chain.proceed(chain.request());
}
}).addInterceptor(new Interceptor() {
@NotNull
@Override
public Response intercept(@NotNull Chain chain) throws IOException {
//前置处理
Request request = chain.request().newBuilder().addHeader("os", "android")
.addHeader("version", "1.0").build();
Response response = chain.proceed(request);
//后置处理
return response;
}
}).build();
Request request = new Request.Builder().url("https://www.httpbin.org/get?a=1&b=2").build();
// 准备好请求的Call对象
Call call = okHttpClient.newCall(request);
try {
Response response = call.execute();
System.out.println(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
Cookie是某些网站为了辨别用户身份,进行会话跟踪(比如确定登陆状态)而储存在用户本地终端上的数据(通常经过加密),由用户客户端计算机暂时或永久保存的信息
关于cookie的使用:
public class CookieUnitTest {
Map<String, List<Cookie>> cookies = new HashMap<>();
@Test
public void cookieTest() {
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.cookieJar(new CookieJar() {
@Override
public void saveFromResponse(@NotNull HttpUrl httpUrl, @NotNull List<Cookie> list) {
cookies.put(httpUrl.host(), list);
}
@NotNull
@Override
public List<Cookie> loadForRequest(@NotNull HttpUrl httpUrl) {
List<Cookie> cookies = CookieUnitTest.this.cookies.get(httpUrl.host());
return cookies == null ? new ArrayList<>() : cookies;
}
})
.build();
FormBody formBody = new FormBody.Builder().add("username", "lanceedu")
.add("password", "123123").build();
Request request = new Request.Builder().url("https://www.wanandroid.com/user/login")
.post(formBody).build();
// 准备好请求的Call对象
Call call = okHttpClient.newCall(request);
try {
Response response = call.execute();
System.out.println(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
request = new Request.Builder().url("https://www.wanandroid.com/lg/collect/list/0/json")
.build();
// 准备好请求的Call对象
call = okHttpClient.newCall(request);
try {
Response response = call.execute();
System.out.println(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}
返回的数据:
{"data":{"admin":false,"chapterTops":[],"coinCount":2542,"collectIds":[17188,18965,20087,19623],"email":"","icon":"","id":86459,"nickname":"lanceedu","password":"","publicName":"lanceedu","token":"","type":0,"username":"lanceedu"},"errorCode":0,"errorMsg":""}
{"data":{"curPage":1,"datas":[{"author":"xiaoyang","chapterId":440,"chapterName":"官方","courseId":13,"desc":"<p>Gson大家一定不陌生,在很多项目中都大规模使用。</p>\r\n<p>例如常见的:</p>\r\n<pre><code>网络请求\r\n ->返回Json数据\r\n ->Gson解析为对象\r\n ->渲染页面\r\n</code></pre><p>很多时候,历史项目包含很多Gson解析对象在UI线程的操作,或者说即使在子线程其实也会影响页面展现速度。</p>\r\n<p>大家都了解Gson对于对象的解析,如果不单独的配置TypeAdapter,那么其实内部是充满反射的。</p>\r\n<p>问题来了:</p>\r\n<p><strong>有没有什么低侵入的方案可以尽可能去除反射操作,从而提升运行效率?描述思路即可。</strong></p>","envelopePic":"","id":223224,"link":"https://wanandroid.com/wenda/show/19623","niceDate":"2021-10-15 16:52","origin":"","originId":19623,"publishTime":1634287963000,"title":"每日一问 | Gson中序列化对象的操作有低侵入的优化方案吗?","userId":86459,"visible":0,"zan":0},{"author":"xiaoyang","chapterId":360,"chapterName":"小编发布","courseId":13,"desc":"<p>这是一个收集建议、功能的帖子。</p>\r\n<p>如果你有:</p>\r\n<ol>\r\n<li>想要添加的功能;</li>\r\n<li>觉得目前需要改进的地方;</li>\r\n</ol>\r\n<p>欢迎提出,会在评估后安排更新~</p>","envelopePic":"","id":223223,"link":"https://www.wanandroid.com/wenda/show/20087","niceDate":"2021-10-15 16:51","origin":"","originId":20087,"publishTime":1634287899000,"title":"给 wanandroid 提个意见吧!","userId":86459,"visible":0,"zan":0},{"author":"xiaoyang","chapterId":440,"chapterName":"官方","courseId":13,"desc":"<p>关于 Activity 重建,我们探究几个问题:</p>\r\n<ol>\r\n<li>当前 app 正在前台运行,不在栈顶的 Activity 有可能会因为系统资源,例如内存等不足回收吗?</li>\r\n<li>当 app 处于后台运行,app 进程未被杀死,其内部的 Activity 会被回收吗?</li>\r\n<li>当 app 处于后台运行,app 的进程会被杀死吗?</li>\r\n</ol>\r\n<p>如果有能力,建议解释过程中可以配合源码,不一定要全部答出来~</p>","envelopePic":"","id":210658,"link":"https://www.wanandroid.com/wenda/show/18965","niceDate":"2021-08-03 10:43","origin":"","originId":18965,"publishTime":1627958636000,"title":"每日一问 | 关于 Activity 重建,值得探究的几个问题","userId":86459,"visible":0,"zan":0},{"author":"","chapterId":502,"chapterName":"自助","courseId":13,"desc":"","envelopePic":"","id":173169,"link":"https://mp.weixin.qq.com/s/N4e6AkhNgI3mcbWFlqhYPQ","niceDate":"2021-02-05 17:22","origin":"","originId":17188,"publishTime":1612516968000,"title":"Gradle系列之初识Gradle篇","userId":86459,"visible":0,"zan":0}],"offset":0,"over":true,"pageCount":1,"size":20,"total":4},"errorCode":0,"errorMsg":""}
PS:这里使用的是玩安卓的API(只有保持登录状态后才能访问收藏的文章):https://www.wanandroid.com/blog/show/2
关于cookie的现状:链接