OkHttp 的使用与跳坑示例

mark

OkHttp 是一个优秀的网络请求框架,我开始接触 Android 开发的时候就用过这个网络请求框架,官方的参考文档在这里 https://square.github.io/okhttp/ ,本文演示了使用 OkHttp 框架进行简单的 Get、Post(表单形式和 JSON 形式)、Delete、附加请求头、请求异步回调,文件的上传和下载等常用操作。最后记录了一个今天调试了很久的坑,那就是 response.body ().string () 只能有效调用一次,注意 Debug 的时候对结果造成的改变!JDK9 的 HttpURLConnection 有很多变化,下次博客中会有演示和说明。

首选引入这个依赖就可以使用 OkHTTP 了

1
2
3
4
5
6
7
8
9
10
11
12
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.6.0</version>
</dependency>

<!-- 这个是我演示 Post 请求 JSON 格式的时候用到的 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>

如果是 gradle 管理的项目,则只需要引入:

1
compile 'com.squareup.okhttp3:okhttp:3.6.0'

1、Get 请求示例

1
2
3
4
5
6
7
8
9
String url = "http://zouchanglin.cn";
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder ().get ().url (url).build ();
try {
Response execute = okHttpClient.newCall (request).execute ();
System.out.println (execute.body ().string ());
} catch (IOException e) {
e.printStackTrace ();
}

2、Post 请求示例

1、JSON 请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static void main(String [] args) {
String url = "http://zouchanglin.cn/info/create";
OkHttpClient okHttpClient = new OkHttpClient();
Map<String, Object> map = new HashMap<>();
map.put ("name", "Mike");
map.put ("age", "20");
RequestBody requestBody = RequestBody.create (
MediaType.parse ("application/json; charset=utf-8"),
JSONObject.toJSONString (map));
Request request = new Request.Builder ().post (requestBody).url (url).build ();
try {
Response response = okHttpClient.newCall (request).execute ();
System.out.println (response.body ().string ());
} catch (IOException e) {
e.printStackTrace ();
}
}

2、表单数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void main(String [] args) {
String url = "http://zouchanglin.cn/info/create";
OkHttpClient okHttpClient = new OkHttpClient();
RequestBody requestBody = new FormBody.Builder ()
.add ("name", "Mike")
.add ("age", "20").build ();
Request request = new Request.Builder ().post (requestBody).url (url).build ();
try {
Response response = okHttpClient.newCall (request).execute ();
System.out.println (response.body ().string ());
} catch (IOException e) {
e.printStackTrace ();
}
}

3、Delete 请求示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void main(String [] args) {
String url = "http://zouchanglin.cn/info/remove";
OkHttpClient okHttpClient = new OkHttpClient();
RequestBody requestBody = new FormBody.Builder ()
.add ("id", "001002003004").build ();
Request request = new Request.Builder ()
.delete (requestBody).url (url).build ();
try {
Response response = okHttpClient.newCall (request).execute ();
System.out.println (response.body ().string ());
} catch (IOException e) {
e.printStackTrace ();
}
}

4、附加请求头示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static void main(String [] args) {
String url = "http://zouchanglin.cn/info/remove";
OkHttpClient okHttpClient = new OkHttpClient();
RequestBody requestBody = new FormBody.Builder ()
.add ("id", "001002003004").build ();
Request request = new Request.Builder ()
.delete (requestBody)
.addHeader ("Accept", "application/vnd..")
.url (url).build ();
try {
Response response = okHttpClient.newCall (request).execute ();
System.out.println (response.body ().string ());
} catch (IOException e) {
e.printStackTrace ();
}
}

5、请求异步回调示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static void main(String [] args) {
String url = "http://zouchanglin.cn/info/remove";
OkHttpClient okHttpClient = new OkHttpClient();
RequestBody requestBody = new FormBody.Builder ()
.add ("id", "0010003004").build ();
Request request = new Request.Builder ().delete (requestBody).url (url).build ();
Call call = okHttpClient.newCall (request);
call.enqueue (new Callback() {
@Override
public void onFailure(Call call, IOException e) {
//TODO...
}

@Override
public void onResponse(Call call, Response response) throws IOException {
//TODO...
}
});
}

6、上传文件加参数示例

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
26
27
28
29
30
31
32
33
34
35
36
37
38
@PostMapping ("upload")
public String uploadToRemoteHost(String ip, String path, String fileId) {
String url = String.format ("http://% s:8080//api/host/file/create/", ip);
// 找到文件对象
Optional<ImageFile> bigFileById = fileService.getBigFileById (fileId);
if(bigFileById.isPresent ()){
ImageFile imageFile = bigFileById.get ();
OkHttpClient okHttpClient = new OkHttpClient();
MultipartBody.Builder requestBody = new MultipartBody.Builder ();
requestBody.setType (MultipartBody.FORM);
RequestBody body = RequestBody.create (
MediaType.parse ("application/octet-stream"),
imageFile.getContent ().getData ());

// 参数分别为 请求 key 文件名称 RequestBody
requestBody.addFormDataPart ("file", imageFile.getName (), body);
// 要上传的文字参数
Map<String, String> map = new HashMap<>();
map.put ("name", imageFile.getName ());
map.put ("path", path);
for (String key : map.keySet ()) {
requestBody.addFormDataPart (key, map.get (key));
}
MultipartBody build = requestBody.build ();
try {
Request request = new Request.Builder ().post (build).url (url).build ();
Response execute = okHttpClient.newCall (request).execute ();
if(execute.isSuccessful ()){
return execute.body ().string ();
}
return JSONObject.toJSONString (ResultVOUtil.error (1, " 网络错误 & quot;));
} catch (IOException e) {
e.printStackTrace ();
return JSONObject.toJSONString (ResultVOUtil.error (2, " 网络错误 2"));
}
}
return JSONObject.toJSONString (ResultVOUtil.error (3, " 文件不存在 & quot;));
}

7、下载文件示例

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
26
27
28
29
30
31
32
33
34
public void downloadImg(View view){
OkHttpClient client = new OkHttpClient();
final Request request = new Request.Builder ().get ()
.url ("http://wwwx.yyy/a.png")
.build ();
Call call = client.newCall (request);
call.enqueue (new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e ("moer", "onFailure: ");;
}

@Override
public void onResponse(Call call, Response response) throws IOException {
// 拿到字节流
InputStream is = response.body ().byteStream ();

int len = 0;
File file = new File(Environment.getExternalStorageDirectory (), "n.png");
FileOutputStream fos = new FileOutputStream(file);
byte[] buf = new byte[128];

while ((len = is.read (buf)) != -1){
fos.write (buf, 0, len);
}

fos.flush ();
// 关闭流
fos.close ();
is.close ();
}
});
}

8、OkHttp 的坑

OkHttp 请求回调中 response.body ().string () 只能有效调用一次,调用 response.body ().string () 的时候数据流已经关闭了,再次调用就是提示已经 closed,抛出 java.lang.IllegalStateException: closed 异常,所以这个坑还是有点大,我在 debug 的时候由于已经监视了一次 response.body ().string () 的返回值,在代码中跑完就是 IllegalStateException。 调试代码调试时,表达式的监视有时候会影响代码的运行,比如就像 OkHttp 这种情况。