一、概念
是由Square公司开发的一套高效、轻量的HTTP客户端库,支持HTTP/1.1、HTTP/2、HTTP/3(QUIC)及HTTPS,广泛用于Android和Java项目中,它封装了底层网络通信细节,提供了简洁的API。
| 连接池复用 | 通过ConnectionPool管理TCP连接的复用(基于HTTP的keep-alive机制),避免频繁创建/销毁连接的开销(原生API需手动管理,复杂且低效)。 |
| 拦截器机制 | 提供分层拦截器(应用拦截器、网络拦截器),可轻松实现请求头统一处理、日志打印、缓存控制、签名验证等功能(原生API需手动嵌入代码,耦合度高)。 |
| 自动处理常见场景 | 支持自动重定向(3xx状态码)、自动重试(如连接失败)、Gzip压缩解压(减少数据传输量),原生API需手动实现这些逻辑。 |
| 异步回调简化 | 内置异步请求机制(enqueue()),回调在子线程执行,避免Handler+Thread的繁琐代码(原生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 | 用途:提交ByteString(OkHttp的高效字节容器)数据。 |
| 适用场景:内存中已存在的二进制数据(如加密后的字节流)。 |
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; charset=utf-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.0'
2.2 创建 OkHttpClient
OkHttpClient 是线程安全的,全局单例(避免重复创建连接池等资源)即可满足所有请求需求,如需不同配置(如不同超时),可创建多个OkHttpClient实例。
object MyClient {
//创建客户端
private val okHttpClient by lazy {
OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS) //连接超时时间
.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?userId=123")
.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())
}
})
}
三、日志打印
implementation 'com.squareup.okhttp3:logging-interceptor:4.12.0'
//日志打印级别:BASEIC(请求/响应行)、HEADER(请求/响应行+头)、BODY(请求/响应航+头+体)、NONE(不打印)
private val loggingInterceptor by lazy {
HttpLoggingInterceptor().apply {
//仅在debug模式下打印详细(BODY),release模式禁用或简化(BASIC)
level = if (Constants.IS_DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE
}
}
//设置给OkHttoClient
private val okHttpClient = OkHttpClient.Builder()
.addInterceptor(loggingInterceptor) //应用拦截器,打印所有网络请求
// .addNetworkInterceptor(loggingInterceptor) //网络拦截器,只打印真实网络请求


2289

被折叠的 条评论
为什么被折叠?



