1. 项目概述在Android开发中网络请求是每个应用都绕不开的核心功能。OkHttp和Retrofit作为Square公司推出的黄金搭档已经成为现代Android网络请求的事实标准。OkHttp提供了高效的底层HTTP客户端实现而Retrofit则在此基础上构建了类型安全的RESTful API封装层。我仍然记得第一次接触Retrofit时的惊艳感——原来网络请求可以如此优雅通过简单的接口定义就能完成复杂的网络操作再也不用面对冗长的HttpURLConnection代码。本文将带你从零开始掌握这对黄金组合的使用技巧包括基础配置、高级功能以及我在实际项目中积累的实战经验。2. 环境准备与基础配置2.1 依赖引入首先在模块的build.gradle文件中添加必要依赖。建议使用最新稳定版本截至2023年7月dependencies { // OkHttp核心库 implementation com.squareup.okhttp3:okhttp:4.10.0 // Retrofit核心库 implementation com.squareup.retrofit2:retrofit:2.9.0 // Gson转换器 implementation com.squareup.retrofit2:converter-gson:2.9.0 // 日志拦截器调试用 implementation com.squareup.okhttp3:logging-interceptor:4.10.0 }注意Retrofit 2.6.0开始需要Java 8或Android API 21。如果你的项目需要支持更低版本可以考虑使用Retrofit 2.5.0。2.2 基础配置实例创建Retrofit实例是使用的第一步典型的配置如下val okHttpClient OkHttpClient.Builder() .addInterceptor(HttpLoggingInterceptor().apply { level if (BuildConfig.DEBUG) { HttpLoggingInterceptor.Level.BODY } else { HttpLoggingInterceptor.Level.NONE } }) .connectTimeout(30, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .writeTimeout(30, TimeUnit.SECONDS) .build() val retrofit Retrofit.Builder() .baseUrl(https://api.example.com/) .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create()) .build()这里有几个关键点需要注意日志拦截器只在调试模式启用避免生产环境泄露敏感信息超时设置应根据实际业务需求调整电商类应用可能需要更短的超时baseUrl必须以斜杠结尾否则会抛出IllegalArgumentException3. API接口定义与使用3.1 基础请求定义Retrofit的核心魅力在于通过接口定义网络请求。以下是一个完整的示例interface UserService { GET(users/{id}) suspend fun getUser(Path(id) userId: String): ResponseUser POST(users) suspend fun createUser(Body user: User): ResponseCreateUserResponse GET(users) suspend fun listUsers( Query(page) page: Int, Query(size) size: Int 20 ): ResponseListUser Multipart POST(avatar) suspend fun uploadAvatar( Part file: MultipartBody.Part, Part(description) description: RequestBody ): ResponseUploadResult }3.2 注解详解Retrofit提供了丰富的注解来控制请求行为方法注解定义HTTP方法GET, POST, PUT等参数注解Path - 替换URL中的路径参数Query - 添加查询参数Body - 请求体会自动使用配置的Converter转换Header - 添加请求头Field - 表单字段需与FormUrlEncoded配合使用3.3 响应处理Retrofit支持多种响应处理方式// 方式1直接返回实体类自动解析 GET(users/{id}) suspend fun getUser(Path(id) userId: String): User // 方式2返回Response对象包含响应元信息 GET(users/{id}) suspend fun getUser(Path(id) userId: String): ResponseUser // 方式3返回原始ResponseBody GET(users/{id}) suspend fun getUser(Path(id) userId: String): ResponseBody实际项目中推荐使用Response包装可以获取状态码、头部等信息便于错误处理。4. 高级功能与实战技巧4.1 自定义拦截器OkHttp的拦截器机制非常强大可以实现各种定制功能class AuthInterceptor(private val tokenProvider: () - String?) : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val request chain.request().newBuilder() .apply { tokenProvider()?.let { token - addHeader(Authorization, Bearer $token) } } .build() return chain.proceed(request) } } // 使用方式 OkHttpClient.Builder() .addInterceptor(AuthInterceptor { userManager.getToken() }) .build()4.2 文件上传下载文件上传需要使用Multipart// 上传文件 val filePart MultipartBody.Part.createFormData( file, file.name, file.asRequestBody(image/*.toMediaType()) ) val descriptionPart avatar image.toRequestBody(text/plain.toMediaType()) userService.uploadAvatar(filePart, descriptionPart) // 下载文件 Streaming GET(files/{id}) suspend fun downloadFile(Path(id) fileId: String): ResponseResponseBody注意大文件下载必须使用Streaming注解避免一次性加载到内存。4.3 自定义Converter当需要处理特殊数据格式时可以自定义Converterclass XmlConverterFactory : Converter.Factory() { override fun responseBodyConverter( type: Type, annotations: ArrayAnnotation, retrofit: Retrofit ): ConverterResponseBody, * { return Converter { value - parseXml(value.string(), type) } } // 实现parseXml方法... } // 使用方式 Retrofit.Builder() .addConverterFactory(XmlConverterFactory()) // ...5. 常见问题与解决方案5.1 网络请求失败处理建议统一封装错误处理逻辑suspend fun T safeApiCall(apiCall: suspend () - ResponseT): ResultT { return try { val response apiCall() if (response.isSuccessful) { Result.success(response.body()!!) } else { Result.failure(parseError(response.errorBody())) } } catch (e: Exception) { Result.failure(mapException(e)) } } // 使用示例 val result safeApiCall { userService.getUser(123) } when (result) { is Result.Success - { /* 处理成功 */ } is Result.Failure - { /* 处理失败 */ } }5.2 多BaseUrl支持在微服务架构中可能需要访问不同域名的APIval retrofit Retrofit.Builder() .baseUrl(http://placeholder.com/) // 必须设置但不会实际使用 .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create()) .build() // 动态设置BaseUrl的Interceptor class BaseUrlInterceptor : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val originalRequest chain.request() val newUrl originalRequest.url.newBuilder() .host(getHostForRequest(originalRequest)) .build() val newRequest originalRequest.newBuilder() .url(newUrl) .build() return chain.proceed(newRequest) } private fun getHostForRequest(request: Request): String { // 根据请求特征返回对应的host } }5.3 缓存策略配置合理配置缓存可以显著提升用户体验val cacheSize 10 * 1024 * 1024 // 10MB val cache Cache(File(context.cacheDir, http_cache), cacheSize.toLong()) val okHttpClient OkHttpClient.Builder() .cache(cache) .addInterceptor(CacheInterceptor()) .addNetworkInterceptor(OnlineCacheInterceptor()) .build() class CacheInterceptor : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { var request chain.request() if (!NetworkUtil.isNetworkAvailable(context)) { request request.newBuilder() .header(Cache-Control, public, only-if-cached, max-stale3600) .build() } return chain.proceed(request) } }6. 性能优化建议6.1 连接池优化OkHttp默认使用连接池复用连接但可以进一步优化val connectionPool ConnectionPool( maxIdleConnections 5, // 最大空闲连接数 keepAliveDuration 5, // 保持时间(分钟) timeUnit TimeUnit.MINUTES ) val okHttpClient OkHttpClient.Builder() .connectionPool(connectionPool) .build()6.2 请求合并与批处理对于高频小请求可以考虑合并POST(batch) suspend fun batchRequests(Body requests: ListBatchRequestItem): ResponseBatchResponse // 使用示例 val batchResult userService.batchRequests(listOf( BatchRequestItem(GET, /users/1), BatchRequestItem(GET, /users/2) ))6.3 取消请求机制避免内存泄漏和无效请求private val callMap mutableMapOfString, Call() fun fetchUser(userId: String) { val call userService.getUser(userId) callMap[userId] call call.enqueue(object : CallbackUser { override fun onResponse(call: Call, response: ResponseUser) { callMap.remove(userId) // 处理响应 } override fun onFailure(call: Call, t: Throwable) { callMap.remove(userId) // 处理失败 } }) } fun cancelRequest(userId: String) { callMap[userId]?.cancel() callMap.remove(userId) }7. 测试策略7.1 Mock Server测试使用MockWebServer进行接口测试val mockWebServer MockWebServer() Before fun setup() { mockWebServer.start() val retrofit Retrofit.Builder() .baseUrl(mockWebServer.url(/)) .client(OkHttpClient()) .addConverterFactory(GsonConverterFactory.create()) .build() service retrofit.create(UserService::class.java) } Test fun testGetUser() runBlocking { mockWebServer.enqueue(MockResponse() .setBody({id:123,name:test}) .setResponseCode(200)) val response service.getUser(123) assertThat(response.isSuccessful).isTrue() assertThat(response.body()?.name).isEqualTo(test) } After fun tearDown() { mockWebServer.shutdown() }7.2 流量统计监控网络请求情况class MetricsInterceptor : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val request chain.request() val startNs System.nanoTime() val response chain.proceed(request) val tookMs (System.nanoTime() - startNs) / 1_000_000 val contentLength response.body?.contentLength() ?: -1 // 上报指标 metricsCollector.report( url request.url.toString(), method request.method, status response.code, duration tookMs, size contentLength ) return response } }8. 项目结构建议对于大型项目建议采用分层结构network/ ├── api/ │ ├── UserService.kt │ ├── ProductService.kt │ └── ... ├── interceptors/ │ ├── AuthInterceptor.kt │ ├── LoggingInterceptor.kt │ └── ... ├── models/ │ ├── requests/ │ └── responses/ ├── converters/ ├── RetrofitClient.kt └── ApiResult.kt关键文件说明RetrofitClient.kt单例管理Retrofit实例ApiResult.kt统一封装API返回结果interceptors/存放各类拦截器converters/自定义转换器实现9. 兼容性考虑9.1 多平台支持Retrofit不仅支持Android也可用于Java/Kotlin后端项目// JVM项目配置示例 val retrofit Retrofit.Builder() .baseUrl(http://internal.api.com/) .client(OkHttpClient()) .addConverterFactory(JacksonConverterFactory.create()) .build()9.2 与协程/RxJava配合Retrofit天然支持协程和RxJava// 协程版本 GET(users) suspend fun getUsers(): ListUser // RxJava版本 GET(users) fun getUsers(): ObservableListUser // Flow版本 GET(users) fun getUsers(): FlowListUser10. 安全最佳实践10.1 证书锁定防止中间人攻击val certificatePinner CertificatePinner.Builder() .add(api.example.com, sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) .build() val okHttpClient OkHttpClient.Builder() .certificatePinner(certificatePinner) .build()10.2 敏感信息保护避免日志泄露敏感数据class RedactingInterceptor : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val request chain.request() val response chain.proceed(request) if (!BuildConfig.DEBUG) { return response } val contentType response.body?.contentType() if (contentType?.subtype json) { val bodyString response.body?.string() ?: return response val redactedBody redactSensitiveData(bodyString) val newBody ResponseBody.create(contentType, redactedBody) return response.newBuilder().body(newBody).build() } return response } private fun redactSensitiveData(json: String): String { // 实现敏感字段脱敏逻辑 } }11. 调试技巧11.1 使用Stetho调试Facebook的Stetho工具可以方便地查看网络请求implementation com.facebook.stetho:stetho:1.6.0 implementation com.facebook.stetho:stetho-okhttp3:1.6.0val okHttpClient OkHttpClient.Builder() .addNetworkInterceptor(StethoInterceptor()) .build()11.2 请求标记为每个请求添加唯一标识便于追踪class RequestIdInterceptor : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val request chain.request().newBuilder() .addHeader(X-Request-ID, UUID.randomUUID().toString()) .build() return chain.proceed(request) } }12. 未来演进随着Kotlin多平台(KMP)的发展Retrofit也在不断进化。目前已经可以通过Kotlin的expect/actual机制实现多平台共享网络层代码。同时HTTP/3的支持也在路线图中未来在移动端将能获得更快的网络性能。在实际项目中我建议保持对OkHttp和Retrofit新版本的关注但不要盲目升级。每次升级前应在测试环境充分验证特别是注意ProGuard规则的变化。