Java中发送Http请求之OkHttpClient

Java中Http请求的方式很多, OkHttpClient因其独特的特性,非常适合在常见的场景中使用.

1 OkHttpClient的简介

1 OkHttpClient说明

OkHttpClient是一个高效的HTTP客户端,其特性包含:

  • 支持HTTP/2,允许所有同一个主机地址的请求共享同一个socket连接
  • 连接池减少请求延时
  • 透明的GZIP压缩减少响应数据的大小
  • 缓存响应内容,避免一些完全重复的请求

2 OkHttpClient使用步骤

  • 创建OkHttpClient对象
  • 创建Request对象
  • 将Request 对象封装为Call
  • 通过Call 来执行同步或异步请求,调用execute方法同步执行,调用enqueue方法异步执行

3 OkHttpClient案例

@Slf4j
public class OkHttpDemo {
    
    

    // 创建OkHttpClient对象, 并设置超时时间 添加拦截器LoginInterceptor
    private static final OkHttpClient okHttpClient = new OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
        	.addInterceptor(new LoginInterceptor())
            .build();

    public static void main(String[] args) throws IOException {
    
    
        String url = "http://www.baidu.com";
        Request request = new Builder()
                .url(url)
                .get() // 不写,默认是GET请求
                .build();
		
        Call call = okHttpClient.newCall(request);
        // 异步调用
        call.enqueue(new Callback() {
    
    
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
    
    
                log.info("请求失败,异常信息为: {}", e.getMessage());
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response)
                    throws IOException {
    
    
                log.info("请求成功,返回信息为: {}", response.body().toString());
            }
        });
    }
}    

Interceptor拦截器

@Slf4j
public class LoginInterceptor implements Interceptor {
    
    

    /**
     * 统计登录接口完成时间
     */
    @NotNull
    @Override
    public Response intercept(@NotNull Chain chain) throws IOException {
    
    

        Request request = chain.request();
        long begin = System.currentTimeMillis();
        Response  response = chain.proceed(request);
        long end = System.currentTimeMillis();

        // 请求路径中有/login 统计花费时间
        if (request.url().toString().contains("/login")) {
    
    
            log.info("接口处理总用时: {} ", end - begin);
        }

        return response;
    }
}

OkHttpClient对象

通过其内部类Builder的构造器模式,进行属性参数的初始化,常见的包括: 任务调度,协议,连接池,连接超时,读取超时等属性.

 public static final class Builder {
    
    
      @NotNull
      private Dispatcher dispatcher;
      @NotNull
      private ConnectionPool connectionPool;
      @NotNull
      private final List interceptors;
      private int callTimeout;
      private int connectTimeout;
      private int readTimeout;
      private int writeTimeout;
      private int pingInterval;
      private long minWebSocketMessageToCompress;
      @Nullable
      private RouteDatabase routeDatabase;
     
 }

Request对象

通过其内部类构造器模式,进行属性参数的初始化,常见的包括: 请求地址url,请求方式,请求头,请求体,标签参数等, 并且该构造中默认是GET请求.

  open class Builder {
    
    
    internal var url: HttpUrl? = null
    internal var method: String
    internal var headers: Headers.Builder
    internal var body: RequestBody? = null

    /** A mutable map of tags, or an immutable empty map if we don't have any. */
    internal var tags: MutableMap<Class<*>, Any> = mutableMapOf()

    constructor() {
    
    
      this.method = "GET"
      this.headers = Headers.Builder()
    }

    internal constructor(request: Request) {
    
    
      this.url = request.url
      this.method = request.method
      this.body = request.body
      this.tags = if (request.tags.isEmpty()) {
    
    
        mutableMapOf()
      } else {
    
    
        request.tags.toMutableMap()
      }
      this.headers = request.headers.newBuilder()
    }
  }

Call对象

通过OkHttpClient和Request对象构造Call对象,Call接口的唯一实现类RealCall. 其execute方法表示同步执行, enqueue方法表示异步执行.

    override fun execute(): Response {
    
    
    check(executed.compareAndSet(false, true)) {
    
     "Already Executed" }

    timeout.enter()
    callStart()
    try {
    
    
      client.dispatcher.executed(this)
      return getResponseWithInterceptorChain()
    } finally {
    
    
      client.dispatcher.finished(this)
    }
  }

   override fun enqueue(responseCallback: Callback) {
    
    
    check(executed.compareAndSet(false, true)) {
    
     "Already Executed" }

    callStart()
    client.dispatcher.enqueue(AsyncCall(responseCallback))
  }

Interceptor拦截器

Interceptor为所有拦截器的接口, 其实现类有 桥接拦截器BridgeInterceptor, 缓存拦截器CacheInterceptor, 服务拦截器CallServerInterceptor, 错误、重定向拦截器RetryAndFollowUpInterceptor, 连接拦截器ConnectInterceptor.

Call中execute方法调用的getResponseWithInterceptorChain()方法, 创建一个拦截器集合容器,首先添加用户自定义的拦截器, 错误、重定向拦截器,桥接拦截器,缓存拦截器,连接拦截器,服务拦截器.

整个拦截器执行链路,按照添加先后顺序执行,即先执行用户自定义拦截器.

  internal fun getResponseWithInterceptorChain(): Response {
    
    
    // Build a full stack of interceptors.
    val interceptors = mutableListOf<Interceptor>()
    interceptors += client.interceptors
    interceptors += RetryAndFollowUpInterceptor(client)
    interceptors += BridgeInterceptor(client.cookieJar)
    interceptors += CacheInterceptor(client.cache)
    interceptors += ConnectInterceptor
    if (!forWebSocket) {
    
    
      interceptors += client.networkInterceptors
    }
    interceptors += CallServerInterceptor(forWebSocket)

    val chain = RealInterceptorChain(
        call = this,
        interceptors = interceptors,
        index = 0,
        exchange = null,
        request = originalRequest,
        connectTimeoutMillis = client.connectTimeoutMillis,
        readTimeoutMillis = client.readTimeoutMillis,
        writeTimeoutMillis = client.writeTimeoutMillis
    )

    var calledNoMoreExchanges = false
    try {
    
    
      val response = chain.proceed(originalRequest)
      if (isCanceled()) {
    
    
        response.closeQuietly()
        throw IOException("Canceled")
      }
      return response
    } catch (e: IOException) {
    
    
      calledNoMoreExchanges = true
      throw noMoreExchanges(e) as Throwable
    } finally {
    
    
      if (!calledNoMoreExchanges) {
    
    
        noMoreExchanges(null)
      }
    }
  }

4 OkHttpClient常用工具类:

@Slf4j
public class OkHttpUtils {
    
    
    
        // 创建OkHttpClient对象, 并设置超时时间 
    private static final OkHttpClient client = new OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .build();

    /**
     * 同步GET请求
     *
     * @param url 请求地址
     */
    public static String getRequest(String url) {
    
    
        try {
    
    
            // 1 创建OkHttpClient对象 
            // 2 构建Request对象
            Request request = new Request.Builder()
                    .get()// 不写默认为GET请求
                    .url(url)
                    .build();
            // 3 发起请求获取响应值
            Response response = client.newCall(request).execute();
            // 4 根据响应结果判断
            if (response.isSuccessful()) {
    
    
                return response.body().string();
            } else {
    
    
                throw new RuntimeException("请求异常,错误码为: " + response.code());
            }
        } catch (Exception e) {
    
    
            log.info("请求失败,错误信息为= {} ", e.getMessage());
        }
        return null;
    }
    
    /**
     * 同步POST请求
     *
     * @param url 请求地址
     * @param params 请求参数
     */
    public static String postRequest(String url, Map<String, String> params) {
    
    

        try {
    
    
            // 1 创建OkHttpClient对象
            // 2 构建请求体
            MultipartBody body = new MultipartBody.Builder()
                    .setType(MediaType.parse("multipart/form-data"))
                    .addFormDataPart("username", params.get("username"))
                    .addFormDataPart("password", params.get("password"))
                    .build();
            // 3 构建Request对象
            Request request = new Request.Builder()
                    .post(body)
                    .url(url)
                    .build();
            // 4 发起请求获取响应值
            Response response = client.newCall(request).execute();

            // 5 根据响应结果判断
            if (response.isSuccessful()) {
    
    
                return response.body().string();
            } else {
    
    
                throw new RuntimeException("请求异常,错误码为: " + response.code());
            }
        } catch (Exception e) {
    
    
            log.info("请求失败,错误信息为= {} ", e.getMessage());
        }
        return null;
    }
    
    
    /**
     * 同步GET请求
     */
    public static String getRequest(String url) throws IOException {
    
    
        Request request = new Builder().url(url).build();
        Response response = execute(request);

        if (response.isSuccessful()) {
    
    
            return response.body().string();
        } else {
    
    
            throw new ArithmeticException("请求异常,错误码为: " + response.code());
        }

    }

    /**
     * 同步请求
     */
    public static Response execute(Request request) throws IOException {
    
    
        return client.newCall(request).execute();
    }
    
    /**
     * 开启异步线程访问网络, 需要返回结果
     */
    public static void enqueue(Request request, Callback callback) {
    
    
        client.newCall(request).enqueue(callback);
    }

    /**
     * 开启异步线程访问网络,不需要返回结果( Callback 返回为空)
     */
    public static void enqueue(Request request) {
    
    
        client.newCall(request).enqueue(new Callback() {
    
    
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
    
    
                log.info("请求失败,异常信息为: {} ", e.getMessage());
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response)
                    throws IOException {
    
    
                log.info("请求成功");
            }
        });
    }
    
}

参考资料:

https://blog.csdn.net/workingman_li/article/details/91651156

https://blog.csdn.net/weixin_44778952/article/details/106338576

https://blog.csdn.net/sinat_34241861/article/details/108261600

https://square.github.io/okhttp/3.x/okhttp/okhttp3/OkHttpClient.html

猜你喜欢

转载自blog.csdn.net/ABestRookie/article/details/121481408