Skip to content

使用 OkHttp 调用接口

🏷️ OkHttp

OkHttp 是一款很强大的网络请求框架。这里学习下如何通过其 OkHttpClient 来发送网络请求。

假设有如下接口:

请求类型URL说明
GET/hello没有参数
GET/hello/{name}从 URL 的 Path 中获取参数
POST/hello从 POST 请求的 Body 中获取参数
POST/hello/from-header从 Header 中获取参数

对应的 HelloController 的代码和这篇博客中的一样,这里就不再重复了。

使用 OkHttp 调用接口的示例代码(测试类):

java
package me.liujiajia.springboot.advanced.ok.http.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import okhttp3.*;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpStatus;

import java.io.IOException;
import java.util.Objects;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
class HelloControllerTest {

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

    @Autowired
    private OkHttpClient client;

    @Test
    void sayHello() throws IOException {
        Request request = new Request.Builder()
                .url("http://localhost:8080/hello")
                .build();

        try (Response response = client.newCall(request).execute()) {
            Assertions.assertEquals(response.code(), HttpStatus.OK.value());
            Assertions.assertEquals(Objects.requireNonNull(response.body()).string(), "Hello,World!");
        }
    }

    @Test
    void sayHelloWithName() throws IOException {
        Request request = new Request.Builder()
                .url(String.format("http://localhost:8080/hello/%s", NAME))
                .build();

        try (Response response = client.newCall(request).execute()) {
            Assertions.assertEquals(response.code(), HttpStatus.OK.value());
            Assertions.assertEquals(Objects.requireNonNull(response.body()).string(), String.format("Hello,%s!", NAME));
        }
    }

    @Test
    void sayHelloWithUserInfo() throws IOException {
        HelloController.UserInfo userInfo = new HelloController.UserInfo();
        userInfo.setName(NAME);

        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writeValueAsString(userInfo);
        RequestBody body = RequestBody.create(json, JSON);

        Request request = new Request.Builder()
                .url("http://localhost:8080/hello")
                .post(body)
                .build();

        try (Response response = client.newCall(request).execute()) {
            Assertions.assertEquals(response.code(), HttpStatus.OK.value());
            Assertions.assertEquals(Objects.requireNonNull(response.body()).string(), String.format("Hello,%s!", NAME));
        }
    }

    @Test
    void sayHelloWithHeader() throws IOException {
        Request request = new Request.Builder()
                .url("http://localhost:8080/hello/from-header")
                .header("name", NAME)
                .post(RequestBody.create("{}", JSON))
                .build();

        try (Response response = client.newCall(request).execute()) {
            Assertions.assertEquals(response.code(), HttpStatus.OK.value());
            Assertions.assertEquals(Objects.requireNonNull(response.body()).string(), String.format("Hello,%s!", NAME));
        }
    }
}

更多 OkHttp 的用法见官方的 Recipes

在 SpringBoot 中使用时需要添加 okhttp 依赖,这里使用的是当前的最新版 4.10.0

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

OkHttpClient 的配置类(参考这篇博客):

java
package me.liujiajia.springboot.advanced.ok.http.config;

import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.TimeUnit;

/**
 * @author 佳佳
 */
@Configuration
public class OkHttpClientConfig {

    @Value("${ok.http.connect-timeout:10}")
    private Integer connectTimeout;

    @Value("${ok.http.read-timeout:10}")
    private Integer readTimeout;

    @Value("${ok.http.write-timeout:10}")
    private Integer writeTimeout;

    @Value("${ok.http.max-idle-connections:5}")
    private Integer maxIdleConnections;

    @Value("${ok.http.keep-alive-duration:5}")
    private Long keepAliveDuration;

    @Bean
    public OkHttpClient okHttpClient() {
        return new OkHttpClient().newBuilder()
                .connectionPool(connectionPool())
                .connectTimeout(connectTimeout, TimeUnit.SECONDS)
                .readTimeout(readTimeout, TimeUnit.SECONDS)
                .writeTimeout(writeTimeout, TimeUnit.SECONDS)
                .hostnameVerifier((hostname, session) -> true)
                // 设置代理
                // .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 8888)))
                // 拦截器
                // .addInterceptor()
                .build();
    }

    private ConnectionPool connectionPool() {
        return new ConnectionPool(maxIdleConnections, keepAliveDuration, TimeUnit.MINUTES);
    }

}

如果希望 RestTemplate 使用 OkHttpClient (默认是 HttpClient)发送网络请求,可以通过如下方式配置:

java
package me.liujiajia.springboot.advanced.ok.http.config;

import okhttp3.OkHttpClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

/**
 * @author 佳佳
 */
@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(ClientHttpRequestFactory clientHttpRequestFactory) {
        RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);
        // 可以添加消息转换
        //restTemplate.setMessageConverters(...);
        // 可以增加拦截器
        //restTemplate.setInterceptors(...);
        return restTemplate;
    }

    @Bean
    public ClientHttpRequestFactory clientHttpRequestFactory(OkHttpClient okHttpClient) {
        return new OkHttp3ClientHttpRequestFactory(okHttpClient);
    }

}