
一、概念是由Square公司开发的一套高效、轻量的HTTP客户端库支持HTTP/1.1、HTTP/2、HTTP/3QUIC及HTTPS广泛用于Android和Java项目中它封装了底层网络通信细节提供了简洁的API。连接池复用通过ConnectionPool管理TCP连接的复用基于HTTP的keep-alive机制避免频繁创建/销毁连接的开销原生API需手动管理复杂且低效。拦截器机制提供分层拦截器应用拦截器、网络拦截器可轻松实现请求头统一处理、日志打印、缓存控制、签名验证等功能原生API需手动嵌入代码耦合度高。自动处理常见场景支持自动重定向3xx状态码、自动重试如连接失败、Gzip压缩解压减少数据传输量原生API需手动实现这些逻辑。异步回调简化内置异步请求机制enqueue()回调在子线程执行避免HandlerThread的繁琐代码原生API需手动管理线程通信。缓存支持内置HTTP缓存基于Cache-Control头可配置磁盘缓存目录和大小实现离线访问原生API需手动处理缓存逻辑易出错。HTTP/2与HTTP/3支持原生支持多路复用HTTP/2和QUIC协议HTTP/3大幅提升并发请求性能原生HttpURLConnection对高版本HTTP支持有限。1.1 RequestBody 类是OkHttp中用于封装POST、PUT等请求的请求体的抽象类。FormBody用途提交表单数据application/x-www-form-urlencoded格式键值对场景简单表单提交如登录、搜索数据为字符串键值对。MultipartBody用途提交混合类型数据multipart/form-data格式支持文本文件。适用场景文件上传如头像、文档同时需携带表单字段。RequestBody.create()用途提交自定义格式数据如JSON、纯文本、二进制。适用场景API接口提交JSON数据、发送纯文本等。ByteStringRequestBody用途提交ByteStringOkHttp的高效字节容器数据。适用场景内存中已存在的二进制数据如加密后的字节流。1.1.1 FormBody// 构建表单数据 FormBody formBody new FormBody.Builder() .add(username, test) .add(password, 123456) .build(); // 构建POST请求 Request request new Request.Builder() .url(https://api.example.com/login) .post(formBody) .build();1.1.2 MultipartBody// 构建文件请求体上传图片 RequestBody fileBody RequestBody.create( new File(/sdcard/avatar.jpg), MediaType.parse(image/jpeg) ); // 构建混合请求体 MultipartBody multipartBody new MultipartBody.Builder() .setType(MultipartBody.FORM) // 必须指定类型为FORM .addFormDataPart(username, test) // 文本字段 .addFormDataPart(avatar, avatar.jpg, fileBody) // 文件字段name、文件名、文件体 .build(); // 构建POST请求 Request request new Request.Builder() .url(https://api.example.com/upload) .post(multipartBody) .build();1.1.3 RequestBody.create() 静态方法创建// JSON数据 String json {\name\:\张三\,\age\:20}; // 创建JSON请求体指定媒体类型为application/json RequestBody jsonBody RequestBody.create( json, MediaType.parse(application/json; charsetutf-8) ); // 构建POST请求 Request request new Request.Builder() .url(https://api.example.com/user) .post(jsonBody) .build();1.2 拦截器 Interceptor拦截器是OkHttp中用于拦截、修改、监控HTTP请求与响应的组件类似“中间件”它可以在请求发送到服务器前处理请求如添加头信息、签名或在响应返回客户端后处理响应如解析数据、打印日志是OkHttp灵活性的核心。无论响应是来自网络还是缓存应用拦截器都会被调用。如果响应来自于缓存网络拦截器将完全不会被调用。对于缓存拦截器一定要用应用拦截器1.2.1 统一添加请求头如Token使用应用拦截器val headerInterceptor object : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { //获取原始请求 val originalRequest chain.request() //构建新请求添加统一头信息如Token val newRequest originalRequest.newBuilder() .addHeader(Authorization, Bearer getToken()) //添加Token .addHeader(App-Version, 1.0.0) // 添加App版本 .build() //继续执行请求 return chain.proceed(newRequest) } fun getToken(): String { return user_token_123456 } } val client OkHttpClient.Builder() .addInterceptor(headerInterceptor) .build()1.2.2 请求/响应日志打印使用应用拦截器或网络拦截器推荐使用官方LoggingInterceptor见下方三val logInterceptor object : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { //打印请求信息 val request chain.request() Log.d(请求头URL, ${request.url}) Log.d(请求头, ${request.headers}) //执行请求 val startTime System.currentTimeMillis() val response chain.proceed(request) val endTime System.currentTimeMillis() //打印响应信息 Log.d(响应码, ${response.code}) Log.d(耗时, ${endTime - startTime} ms) Log.d(响应体, response.body.toString()) return response } } val client OkHttpClient.Builder() .addNetworkInterceptor(logInterceptor) .build()1.2.3 缓存控制使用应用拦截器详见缓存策略主要通过HTTP请求头/响应头的Cache-Control字段控制。通过请求头设置缓存读取策略通过响应头设置缓存保存策略。1.3 连接池 ConnectionPool基于HTTP的keep-alive机制管理TCP连接的复用避免频繁创建/销毁连接的性能损耗TCP三次握手、四次挥手耗时。当请求完成后TCP连接不会立即关闭而是被放入连接池标记为“空闲”。新请求若访问相同的主机和端口且协议版本兼容会优先复用连接池中的空闲连接。连接池通过后台线程CleanupThread定期清理过期连接超过最大存活时间或超出最大空闲数的连接。//高频访问同一服务器可增大最大空闲数减少连接创建开销。 val connectionPool ConnectionPool( maxIdleConnections 10, //最大空闲连接数 keepAliveDuration 10, //存活时间 timeUnit TimeUnit.MINUTES ) val client OkHttpClient.Builder() .connectionPool(connectionPool) .build()二、基本使用2.1 添加依赖implementation com.squareup.okhttp3:okhttp:4.12.02.2 创建 OkHttpClientOkHttpClient 是线程安全的全局单例避免重复创建连接池等资源即可满足所有请求需求如需不同配置如不同超时可创建多个OkHttpClient实例。object MyClient { //创建客户端 private val okHttpClient by lazy { OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) //连接超时10s连不上就是网络差 .readTimeout(10, TimeUnit.SECONDS) //读取超时后端接口慢的兜底 .writeTimeout(10, TimeUnit.SECONDS) //写入超时 //还可添加拦截器、缓存等配置 .build() } }2.3 GET 请求构建Request对象通过Call执行分为同步和异步两种。2.3.1 同步请求 execute()同步请求会阻塞当前线程必须在子线程中执行否则会导致ANR。fun getDemo() Thread { //创建请求 val request Request.Builder() .url(https://www.baidu.com) .get() //默认为GET可省略 .addHeader(Accept,application/json) //可选添加请求头 .build() //创建任务 val call MyClient.okHttpClient.newCall(request) try { //执行任务(同步执行阻塞当前线程) val response call.execute() //处理响应 if (response.code HttpURLConnection.HTTP_OK) { Log.d(成功, response.body.toString()) } else { Log.d(失败, response.code.toString()) } } catch (e: Exception) { e.printStackTrace() } }.start()2.3.2 异步请求 enqueue()异步请求通过回调处理结果不会阻塞当前线程推荐使用.fun getDemo2() { //创建请求 val request Request.Builder() .url(https://api.example.com/user?userId123) .build() //创建任务 val call MyClient.okHttpClient.newCall(request) //执行任务异步执行回调在子线程中 call.enqueue(object : Callback { //请求完成无论成功与否 override fun onResponse(call: Call, response: Response) { if (response.code HttpURLConnection.HTTP_OK) { //反序列化json转bean val dataBean Gson().fromJson(response.body.toString(), DataBean::class.java) } } //请求失败 override fun onFailure(call: Call, e: IOException) { Log.d(失败, e.toString()) } }) }2.2 post请求fun postCall() { //创建客户端 val client OkHttpClient.Builder() .connectTimeout(5000, TimeUnit.MILLISECONDS) .build() //创建要提交的内容序列化内容转bean再转json val dataBean DataBean(张三) val jsonStr Gson().toJson(dataBean) val mediaType application/json.toMediaTypeOrNull() val requestBody jsonStr.toRequestBody(mediaType) //创建请求 val request Request.Builder() .post(requestBody) .url(https://www.baidu.com) .build() //创建任务 val call client.newCall(request) //执行任务 call.enqueue(object : Callback { override fun onFailure(call: Call, e: IOException) { Log.d(ErrorMsg, e.toString()) } override fun onResponse(call: Call, response: Response) { Log.d(Result, response.body.toString()) } }) }三、日志打印[versions] retrofitLogging 5.3.2 [libraries] retrofit-logging { module com.squareup.okhttp3:logging-interceptor, version.ref retrofitLogging }// 日志打印级别BASIC(请求/响应行)、HEADER(请求/响应行头)、BODY(请求/响应航头体)、NONE(不打印) private val loggingInterceptor by lazy { HttpLoggingInterceptor().apply { // 仅在debug模式下打印详细BODYrelease模式禁用NONE或简化BASIC level if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE } } private val okHttpClient by lazy { OkHttpClient.Builder() // 拦截器是链式的越靠后看到的越接近最终发出去的请求。 // 日志放最后写才能看到鉴权头、重试之后的最终形态。 .addInterceptor(loggingInterceptor) //通过应用拦截器打印所有网络请求(推荐如可以看是否用了缓存) // .addNetworkInterceptor(loggingInterceptor) //通过网络拦截器只打印真实网络请求 .build() }