目录

  1. 前言

  2. 为什么要封装 Retrofit + OkHttp

  3. 基础封装思路

  4. 支持多 BaseUrl 的设计

  5. 统一响应模型与错误处理

  6. Token 自动刷新机制

  7. 完整网络层结构

  8. 性能优化与调试建议

  9. 结语


前言

在 Android 项目开发中,网络请求几乎是所有业务模块的基础。而在众多方案中,Retrofit + OkHttp 无疑是最稳定、最高效的组合。

它不仅支持注解式接口定义、自动序列化,还能与协程完美结合,轻松实现异步网络通信。
本文将从基础到进阶,带你实现一套「企业级」网络层封装,让你的代码更优雅、更安全、更可维护。


⚙️ 为什么要封装 Retrofit + OkHttp

在小型项目中,直接使用 Retrofit 足够简单;
但随着业务扩展,你可能会遇到以下痛点:

  • 不同模块需要使用 不同的 BaseUrl

  • 接口响应结构不一致,需要统一解析;

  • Token 失效需要自动刷新;

  • 需要统一的异常处理机制;

  • 想让 ViewModel 调用更简洁。

这些问题如果不统一封装,会导致项目结构混乱、维护困难。
因此,我们需要构建一个「高内聚、低耦合」的网络请求框架。


基础封装思路

Retrofit 是一个「上层封装」,核心依赖 OkHttp:

层级功能说明
OkHttp网络层负责请求发送、拦截、缓存、超时
Retrofit封装层负责接口注解解析、数据转换
协程 + Result安全层负责异常捕获与结果返回

我们将从 OkHttp 开始封装,逐步构建整个网络体系。


支持多 BaseUrl 的设计

1. 使用场景

在多模块项目中,不同业务接口往往属于不同域名:

模块BaseUrl
用户中心https://user.api.example.com/
支付模块https://pay.api.example.com/
上传模块https://upload.api.example.com/

Retrofit 默认只能设置一个 baseUrl
因此我们需要通过 拦截器 + Header 标识 来动态替换。


2. BaseUrlInterceptor.kt

class BaseUrlInterceptor : Interceptor {
    companion object {
        const val HEADER_BASE_URL = "Base-Url" // 自定义 Header 名
    }
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        val baseUrlHeader = request.header(HEADER_BASE_URL)
        // 如果请求头中包含自定义 BaseUrl
        if (!baseUrlHeader.isNullOrEmpty()) {
            val newUrl = request.url.newBuilder()
                .scheme("https")
                .host(baseUrlHeader)
                .build()
            val newRequest = request.newBuilder()
                .url(newUrl)
                .removeHeader(HEADER_BASE_URL) // 使用完后移除
                .build()
            return chain.proceed(newRequest)
        }
        // 默认请求
        return chain.proceed(request)
    }
}

3. RetrofitManager.kt

object RetrofitManager {
    private const val DEFAULT_BASE_URL = "https://user.api.example.com/"
    private val okHttpClient by lazy {
        OkHttpClient.Builder()
            .addInterceptor(BaseUrlInterceptor())
            .addInterceptor(TokenInterceptor())
            .addInterceptor(HttpLoggingInterceptor().apply {
                level = HttpLoggingInterceptor.Level.BODY
            })
            .connectTimeout(10, TimeUnit.SECONDS)
            .readTimeout(15, TimeUnit.SECONDS)
            .build()
    }
    fun getService(baseUrl: String = DEFAULT_BASE_URL): Retrofit {
        return Retrofit.Builder()
            .baseUrl(baseUrl)
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }
}

使用示例:

val userApi = RetrofitManager.getService().create(UserApi::class.java)
val payApi = RetrofitManager.getService("https://pay.api.example.com/").create(PayApi::class.java)

统一响应模型与错误处理

1. 定义统一返回结构

data class BaseResponse(
    val code: Int,
    val msg: String?,
    val data: T?
) {
    fun isSuccess() = code == 200
}

2. 安全请求封装(协程版)

suspend fun  safeApiCall(apiCall: suspend () -> BaseResponse): Result {
    return try {
        val response = apiCall()
        if (response.isSuccess()) {
            Result.success(response.data!!)
        } else {
            Result.failure(Exception(response.msg ?: "未知错误"))
        }
    } catch (e: IOException) {
        Result.failure(Exception("网络连接失败"))
    } catch (e: HttpException) {
        Result.failure(Exception("网络错误: ${e.code()}"))
    } catch (e: Exception) {
        Result.failure(e)
    }
}

3. ViewModel 调用示例

class LoginViewModel : ViewModel() {
    private val _loginState = MutableLiveData>()
    val loginState: LiveData> = _loginState
    fun login(username: String, password: String) {
        viewModelScope.launch {
            val result = safeApiCall {
                RetrofitManager.getService().create(UserApi::class.java)
                    .login(username, password)
            }
            _loginState.value = result
        }
    }
}

Token 自动刷新机制

class TokenInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request().newBuilder()
            .addHeader("Authorization", "Bearer ${TokenManager.token}")
            .build()
        val response = chain.proceed(request)
        // Token 过期处理
        if (response.code == 401) {
            synchronized(this) {
                val newToken = TokenManager.refreshToken()
                if (newToken != null) {
                    val newRequest = request.newBuilder()
                        .removeHeader("Authorization")
                        .addHeader("Authorization", "Bearer $newToken")
                        .build()
                    return chain.proceed(newRequest)
                }
            }
        }
        return response
    }
}

网络层完整结构

network/
├── ApiService.kt          # 接口定义
├── RetrofitManager.kt     # Retrofit 实例
├── BaseUrlInterceptor.kt  # 多域名支持
├── TokenInterceptor.kt    # Token 刷新
├── NetworkHelper.kt       # 安全请求封装
└── model/
    └── BaseResponse.kt    # 统一响应模型

⚡ 性能优化与调试建议

优化项建议
⏱️ 超时设置连接 10s,读取 15s,写入 15s
缓存策略静态接口可添加本地缓存
日志管理Debug 模式启用 BODY,Release 模式关闭
♻️ 连接池复用默认 Keep-Alive,可减少握手时间
异常监控在 Result.failure 中上报错误信息

结语

通过这套封装,我们构建了一个高扩展性、高可维护性的网络层:

层级功能示例
通信层OkHttp超时、缓存、拦截器
封装层Retrofit动态接口映射
逻辑层协程 + Result异常捕获、安全返回
扩展层Token、多 BaseUrl统一管理

这是一套可以直接落地于实际项目的通用网络架构,既简洁又灵活,适用于 MVVM、MVI 等主流架构。