OkHttp使用指南:封装一个好用的Http工具类

4,521 阅读3分钟

个人博客:yaowenbinqwq.github.io/

OkHttp是一个高效的HTTP请求客户端对于Android和Java应用。其有着许多高级的功能,比如线程池、GZip压缩和响应缓存。 同时不仅能够发送同步的请求,也能够支持异步调用。

<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.9.1</version>
</dependency>

同步请求

我们需要基于URL地址来构建一个Reqeust对象,然后调用newCall()来生成一个Call对象,然后调用execute()方法来同步发送请求并获取相应结果

@Test
public void whenGetRequest_thenCorrect() throws IOException {
    Request request = new Request.Builder()
      .url(BASE_URL + "/date")
      .build();

    Call call = client.newCall(request);
    Response response = call.execute();

    assertThat(response.code(), equalTo(200));
}

异步请求

@Test
public void whenAsynchronousGetRequest_thenCorrect() {
    Request request = new Request.Builder()
      .url(BASE_URL + "/date")
      .build();

    Call call = client.newCall(request);
    call.enqueue(new Callback() {
        public void onResponse(Call call, Response response) 
          throws IOException {
            // ...
        }
        
        public void onFailure(Call call, IOException e) {
            fail();
        }
    });
}

添加请求参数

@Test
public void whenGetRequestWithQueryParameter_thenCorrect() 
  throws IOException {
    
    HttpUrl.Builder urlBuilder 
      = HttpUrl.parse(BASE_URL + "/users").newBuilder();
    urlBuilder.addQueryParameter("name", "zhangsan");

    String url = urlBuilder.build().toString();

    Request request = new Request.Builder()
      .url(url)
      .build();
    Call call = client.newCall(request);
    Response response = call.execute();

    assertThat(response.code(), equalTo(200));
}

添加请求体

表单请求

通过FormBody我们能够构造出表单请求(application/x-www-form-urlencoded),使用方式如下:

@Test
public void whenPostRequestWithBody_thenCorrect() 
  throws IOException {
    RequestBody formBody = new FormBody.Builder()
      .add("username", "test")
      .add("password", "test")
      .build();

    Request request = new Request.Builder()
      .url(BASE_URL + "/users")
      .post(formBody)
      .build();

    Call call = client.newCall(request);
    Response response = call.execute();
    
    assertThat(response.code(), equalTo(200));
}

JSON请求

为了适应目前RESTAfulAPI风格的JSON请求格式,OkHttp提供了String类型的json支持,我们可以通过一些json序列化库来帮助我们将一些实体类型转化为json后发送请求:

private MediaType JSON_TYPE = MediaType.get("application/json; charset=utf-8");

@Test
public void whenPostRequestWithJSON_thenCorrect() 
  throws IOException {
    User user = new User().userId(1L).username("yaowenbin");
    String json = JSON.toJSONString(user);
    RequestBody requestBody = RequestBody.create(JSON_TYPE, json);

    Request request = new Request.Builder()
      .url(BASE_URL + "/users")
      .post(formBody)
      .build();

    Call call = client.newCall(request);
    Response response = call.execute();
    
    assertThat(response.code(), equalTo(200));
}

PUT/DELETE请求

PUT/DELETE和POST请求也类似,只不过把Request调用的post方法转化成了对应的put()和delete()罢了

@Test
public void whenPuttRequestWithBody_thenCorrect() 
        throws IOException {
    ...
    Request request = new Request.Builder()
        .put(requestBody)
        .url(BASE_URL + "/users")
        .build();
	...
}

@Test
public void whenPuttRequestWithBody_thenCorrect() 
        throws IOException {
    ...
    Request request = new Request.Builder()
        .delete(requestBody)
        .url(BASE_URL + "/users")
        .build();
	...
}

请求头

单次请求头

我们只需要在Request的Builder中使用addHeader即可在请求中添加请求头了:

@Test
public void whenSetHeader_thenCorrect() throws IOException {
    Request request = new Request.Builder()
      .url(SAMPLE_URL)
      .addHeader("Content-Type", "application/json")
      .build();

    Call call = client.newCall(request);
    Response response = call.execute();
    response.close();
}

全局请求头

如果我们希望每一个发送的请求都能够携带上全局的请求参数,比如说登录Token时,OkHttp使用了Interceptor来帮助我们达到这样的效果:

@Test
public void whenSetDefaultHeader_thenCorrect() 
  throws IOException {
    
    OkHttpClient client = new OkHttpClient.Builder()
      .addInterceptor(
        new DefaultContentTypeInterceptor("application/json"))
      .build();

    Request request = new Request.Builder()
      .url(SAMPLE_URL)
      .build();

    Call call = client.newCall(request);
    Response response = call.execute();
    response.close();
}

封装一个更加易用API

对于序列化工具你想要使用FastJSON2还是Jackson还是Gson都是没有问题的

import com.alibaba.fastjson.JSONObject;
import okhttp3.*;

import java.io.IOException;

/** 
 * @author : yaowenbin
 */
public class HttpUtil {
    static OkHttpClient HTTP_CLIENT = new OkHttpClient.Builder()
            .build();

    public static final MediaType JSON
            = MediaType.get("application/json; charset=utf-8");

    public static String get(String url) {
        Request request = new Request.Builder()
                .get()
                .url(url)
                .build();

        return synchronizedCall(request);
    }

    public static <T> T get(String url, Class<T> clz) {
        return parse(get(url), clz);
    }

    public static String post(String url, String json) {
        RequestBody requestBody = RequestBody.create(JSON, json);
        Request request = new Request.Builder()
                .post(requestBody)
                .url(url)
                .build();

        return synchronizedCall(request);
    }
    public static <T> T post(String url, String json, Class<T> clz) {
        return parse(post(url, json), clz);
    }

    public static String put(String url, String json) {
        RequestBody body = RequestBody.create(JSON, json);

        Request request = new Request.Builder()
                .url(url)
                .put(body)
                .build();

        return synchronizedCall(request);
    }

    public static String put(String url) {
        return put(url, "");
    }


    public static <T> T put(String url, String json, Class<T> clz) {
        return parse(put(url, json), clz);
    }


    public static String delete(String url, String json) {
        RequestBody body = RequestBody.create(JSON, json);

        Request request = new Request.Builder()
                .url(url)
                .delete(body)
                .build();
        return synchronizedCall(request);
    }

    public static String delete(String url) {
        return delete(url, "");
    }

    public static <T> T delete(String url, Class<T> clz) {
        return parse(
                delete(url, ""),
                clz
        );
    }

    public static <T> T delete(String url, String json, Class<T> clz) {
        return parse(delete(url, json), clz);
    }

    private static String synchronizedCall(Request request) {
        try ( Response response = HTTP_CLIENT.newCall(request).execute() ){
            return response.body().toString();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private static<T> T synchronizedCall(Request request, Class<T> clz) {
        return parse(synchronizedCall(request), clz);
    }

    public static <T> T parse(String json, Class<T> clz) {
        return JSONObject.parseObject(json, clz);
    }
}