【笔记】OkHttp学习笔记

前言

HTTP is the way modern applications network. It’s how we exchange data & media. Doing HTTP efficiently makes your stuff load faster and saves bandwidth.(官网

在Android通过使用OkHttp实现发送请求
因为OkHttp是开源的,所以也可以在别的Java项目中使用

引入依赖

app/build.gradle
1
2
3
4
5
6
dependencies {

...

implementation 'com.squareup.okhttp3:okhttp:4.9.0'
}

添加网络权限

  • 在清单文件的<application></application>之外添加网络权限
app/src/main/AndroidManifest.xml
1
<uses-permission android:name="android.permission.INTERNET" />

GET请求

  • 如果有参数,直接追加在请求地址后面

  • GET请求在创建请求对象时,可以调用.get()方法,也可以不调用,因为默认请求方式就是GET请求

同步请求

<url>:请求地址

app/src/main/java/.../MainActivity.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 创建OkHttp客户端对象
OkHttpClient okHttpClient = new OkHttpClient();
// 创建请求对象
// Request request = new Request.Builder().get().url("<url>").build();
Request request = new Request.Builder().url("<url>").build();
// 通过OkHttp客户端对象和请求对象获取Call对象
Call call = okHttpClient.newCall(request);
try {
// 发送同步请求
Response response = call.execute();
// 解析响应
System.out.println(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}

Android同步请求

  • Android发送同步请求时需要再创建一个线程才能正常运行
app/src/main/AndroidManifest.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
new Thread() {
@Override
public void run() {
// 创建OkHttp客户端对象
OkHttpClient okHttpClient = new OkHttpClient();
// 创建请求对象
// Request request = new Request.Builder().get().url("<url>").build();
Request request = new Request.Builder().url("<url>").build();
// 通过OkHttp客户端对象和请求对象获取Call对象
Call call = okHttpClient.newCall(request);
try {
// 发送同步请求
Response response = call.execute();
// 解析响应
System.out.println(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
};

异步请求

app/src/main/AndroidManifest.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 创建OkHttp客户端对象
OkHttpClient okHttpClient = new OkHttpClient();
// 创建请求对象
// Request request = new Request.Builder().get().url("<url>").build();
Request request = new Request.Builder().url("<url>").build();
// 通过OkHttp客户端对象和请求对象获取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 {
// 判断响应码是否在[200,300)区间
if (response.isSuccessful()) {
// 解析响应
System.out.println(response.body().string());
}
}
});

POST请求

<key>:参数名
<value>:参数值

同步请求

app/src/main/AndroidManifest.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 创建OkHttp客户端对象
OkHttpClient okHttpClient = new OkHttpClient();
// 创建请求体对象,将传递的参数添加到请求体
FormBody body = new FormBody.Builder().add("<key>", "<value>").add("<key>", "<value>").build();
// 创建请求对象,需要传递请求体作为参数
Request request = new Request.Builder().post(body).url("<url>").build();
// 通过OkHttp客户端对象和请求对象获取Call对象
Call call = okHttpClient.newCall(request);
try {
// 发送同步请求
Response response = call.execute();
// 解析响应
System.out.println(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}

Android同步请求

  • Android发送同步请求时需要再创建一个线程才能正常运行
app/src/main/AndroidManifest.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
new Thread() {
@Override
public void run() {
// 创建OkHttp客户端对象
OkHttpClient okHttpClient = new OkHttpClient();
// 创建请求体对象,将传递的参数添加到请求体
FormBody body = new FormBody.Builder().add("<key>", "<value>").add("<key>", "<value>").build();
// 创建请求对象,需要传递请求体作为参数
Request request = new Request.Builder().post(body).url("<url>").build();
// 通过OkHttp客户端对象和请求对象获取Call对象
Call call = okHttpClient.newCall(request);
try {
// 发送同步请求
Response response = call.execute();
// 解析响应
System.out.println(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
};

异步请求

app/src/main/AndroidManifest.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 创建OkHttp客户端对象
OkHttpClient okHttpClient = new OkHttpClient();
// 创建请求体对象,将传递的参数添加到请求体
FormBody body = new FormBody.Builder().add("<key>", "<value>").add("<key>", "<value>").build();
// 创建请求对象,需要传递请求体作为参数
Request request = new Request.Builder().post(body).url("<url>").build();
// 通过OkHttp客户端对象和请求对象获取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 {
// 判断响应码是否在[200,300)区间
if (response.isSuccessful()) {
// 解析响应
System.out.println(response.body().string());
}
}
});

POST请求的请求体对象

application/x-www-form-urlencoded

  • 传递Form表单作为参数,默认的POST请求参数类型
1
FormBody body = new FormBody.Builder().add("<key>", "<value>").add("<key>", "<value>").build();

multipart/form-data

  • 传递文件作为参数

<src>:文件存放路径
text/plain:文件类型

1
2
3
4
5
6
7
8
// 创建多个文件对象
File file1 = new File("<src>");
File file2 = new File("<src>");

MultipartBody body = new MultipartBody.Builder()
.addFormDataPart("<key>", file1.getName(), RequestBody.create(file1, MediaType.parse("text/plain")))
.addFormDataPart("<key>", file2.getName(), RequestBody.create(file2, MediaType.parse("text/plain")))
.build();

application/json

  • 传递Json数据作为参数

<json>:JSON格式的字符串

1
RequestBody body = RequestBody.create("<json>", MediaType.parse("application/json"));

添加请求头

  • 在创建请求对象时添加请求头

<key>:请求头键
<value>:请求头值

1
2
3
4
Request request = new Request.Builder().post(body).url("<url>")
.addHeader("<key_1>", "<value_1>")
.addHeader("<key_2>", "<value_2>")
.build();

OkHttp的配置

  • 创建OkHttp客户端对象时,不通过new OkHttpClient()的方式,而是通过OkHttp.BuilderClient().bulid()的方式,在创建对象时添加配置

不加配置

1
OkHttpClient okHttpClient = new OkHttpClient();

配置拦截器

添加一个拦截器

  • 既可以使用.addInterceptor()添加拦截器,也可以使用.addNetworkInterceptor()添加拦截器
    • 它们的区别是:.addNetworkInterceptor()一定在.addInterceptor()的后面执行拦截
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
OkHttpClient okHttpClient = new OkHttpClient.Builder().addInterceptor(new Interceptor() {
@NotNull
@Override
public Response intercept(@NotNull Chain chain) throws IOException {

// 前置处理
...

Response proceed = chain.proceed(chain.request());

// 后置处理
...

return proceed;
}
}).build();

添加多个拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(new Interceptor() {
@NotNull
@Override
public Response intercept(@NotNull Chain chain) throws IOException {

Response proceed = chain.proceed(chain.request());

return proceed;
}
})
.addInterceptor(new Interceptor() {
@NotNull
@Override
public Response intercept(@NotNull Chain chain) throws IOException {

Response proceed = chain.proceed(chain.request());

return proceed;
}
})
.build();

拦截举例

  • 例如载发送请求之前添加请求头
1
2
3
4
5
6
7
8
9
10
11
12
13
OkHttpClient okHttpClient = new OkHttpClient.Builder().addInterceptor(new Interceptor() {
@NotNull
@Override
public Response intercept(@NotNull Chain chain) throws IOException {

// 在请求对象基础上创建个一模一样的请求对象,然后添加请求头
Request request = chain.request().newBuilder().addHeader("<key>", "<value>").build();
// 将新的请求对象传递给拦截器
Response proceed = chain.proceed(request);

return proceed;
}
}).build();

配置缓存

<src>:缓存文件在本机存放路径,指定目录名
1024*1024:缓存文件最大的大小,单位字节

1
2
3
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.cache(new Cache(new File("<src>"), 1024*1024))
.build();

配置Cookie

  • 先在全局声明一个变量用于存放Cookie,也可以保存到文件中
1
List<Cookie> cookies;
  • 然后再设置回调方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.cookieJar(new CookieJar() {
// 接收响应时获取Cookie
@Override
public void saveFromResponse(@NotNull HttpUrl httpUrl, @NotNull List<Cookie> list) {
cookies = list;
}

// 发送请求时携带Cookie
@NotNull
@Override
public List<Cookie> loadForRequest(@NotNull HttpUrl httpUrl) {
// 判断请求地址是否需要传递Cookie
if (httpUrl.host().equals("<url>")) {
return cookies;
}
return null;
}
})
.build();

获取响应头数据

  • 得到响应头所有键和值的数组
1
2
3
4
5
6
Response response = call.execute();

Headers headers = response.priorResponse().networkResponse().headers();
Field namesAndValues = headers.getClass().getDeclaredField("namesAndValues");
namesAndValues.setAccessible(true);
String[] responseHeader = (String[]) namesAndValues.get(headers);

完成

参考文献

哔哩哔哩——Android架构解析
CSDN——小丫么小问号