OkHttp的使用与跳坑示例

mark

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

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

 1<dependency>
 2    <groupId>com.squareup.okhttp3</groupId>
 3    <artifactId>okhttp</artifactId>
 4    <version>3.6.0</version>
 5</dependency>
 6
 7<!-- 这个是我演示Post请求JSON格式的时候用到的 -->
 8<dependency>
 9    <groupId>com.alibaba</groupId>
10    <artifactId>fastjson</artifactId>
11    <version>1.2.47</version>
12</dependency>

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

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

1、Get请求示例

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

2、Post请求示例

1、JSON请求

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

2、表单数据

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

3、Delete请求示例

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

4、附加请求头示例

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

5、请求异步回调示例

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

6、上传文件加参数示例

 1@PostMapping("upload")
 2public String uploadToRemoteHost(String ip, String path, String fileId) {
 3    String url = String.format("http://%s:8080//api/host/file/create/", ip);
 4    //找到文件对象
 5    Optional<ImageFile> bigFileById = fileService.getBigFileById(fileId);
 6    if(bigFileById.isPresent()){
 7        ImageFile imageFile = bigFileById.get();
 8        OkHttpClient okHttpClient = new OkHttpClient();
 9        MultipartBody.Builder requestBody = new MultipartBody.Builder();
10        requestBody.setType(MultipartBody.FORM);
11        RequestBody body = RequestBody.create(
12            MediaType.parse("application/octet-stream"), 
13            imageFile.getContent().getData());
14        
15        // 参数分别为 请求key 文件名称 RequestBody
16        requestBody.addFormDataPart("file", imageFile.getName(), body);
17        //要上传的文字参数
18        Map<String, String> map = new HashMap<>();
19        map.put("name", imageFile.getName());
20        map.put("path", path);
21        for (String key : map.keySet()) {
22            requestBody.addFormDataPart(key, map.get(key));
23        }
24        MultipartBody build = requestBody.build();
25        try {
26            Request request = new Request.Builder().post(build).url(url).build();
27            Response execute = okHttpClient.newCall(request).execute();
28            if(execute.isSuccessful()){
29                return execute.body().string();
30            }
31            return JSONObject.toJSONString(ResultVOUtil.error(1, "网络错误"));
32        } catch (IOException e) {
33            e.printStackTrace();
34            return JSONObject.toJSONString(ResultVOUtil.error(2, "网络错误2"));
35        }
36    }
37    return JSONObject.toJSONString(ResultVOUtil.error(3, "文件不存在"));
38}

7、下载文件示例

 1public void downloadImg(View view){
 2    OkHttpClient client = new OkHttpClient();
 3    final Request request = new Request.Builder().get()
 4            .url("http://wwwx.yyy/a.png")
 5            .build();
 6    Call call = client.newCall(request);
 7    call.enqueue(new Callback() {
 8        @Override
 9        public void onFailure(Call call, IOException e) {
10            Log.e("moer", "onFailure: ");;
11        }
12
13        @Override
14        public void onResponse(Call call, Response response) throws IOException {
15            //拿到字节流
16            InputStream is = response.body().byteStream();
17
18            int len = 0;
19            File file  = new File(Environment.getExternalStorageDirectory(), "n.png");
20            FileOutputStream fos = new FileOutputStream(file);
21            byte[] buf = new byte[128];
22
23            while ((len = is.read(buf)) != -1){
24                fos.write(buf, 0, len);
25            }
26
27            fos.flush();
28            //关闭流
29            fos.close();
30            is.close();
31        }
32    });
33}
34

8、OkHttp的坑

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