Retrofit动态切换域名(BaseUrl)

Retrofit动态切换域名(BaseUrl)

Retrofit只有在创建Retrofit对象时能设置BaseUrl,没有提供动态修改的Api。

1
2
3
4
5
6
val retrofit = Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(ResultCallAdapterFactory.create())
.client(okHttpClient)
.build()

根据不同的使用场景,动态修改url主要有一下几种方式

0x01 @Get,@Post注解配置全路径

熟悉 Retrofit 的开发者应该知道 @Get , @Post 这些标注到每个接口方法上的注解不仅可以传相对路径,还可以传全路径,这样我们就可以做到不同的接口使用不同的 BaseUrl ,从而达到使用多个 BaseUrl 的需求,但是注解上的值只能是 Final 的常量,不能动态改变,所以我称这个解决方案为静态解决方案

1
2
3
4
5
@GET("https://developer.android.com/login")
fun login(
@Query("mobile") mobile: String,
@Query("code") code: String
): Call<ResponseBody>

0x02 @Url支持全路径地址

熟悉 Retrofit 的开发者也同样知道 @Url 这个标注到每个接口方法参数上的注解,它可以将全路径作为参数传进接口作为每次请求的 Url 地址,每次请求接口都可以将不同的全路径作为参数,从而达到支持多个 BaseUrl 以及在运行时动态改变 BaseUrl ,所以很多请求图片等资源的接口都是使用这个方案

1
2
3
4
5
6
@GET
fun login(
@Url url: String,
@Query("mobile") mobile: String,
@Query("code") code: String
): Call<ResponseBody>

0x03 多个Retrofit对象

即不同的 BaseUrl 使用不同的 Retrofit 对象。缺点是只要新增一个BaseUrl,就需要创建一个新的 Retrofit 对象

0x04 OkHttpClient添加域名切换拦截器

自定义域名切换拦截器HostInterceptor,动态切换BaseUrl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class HostInterceptor: Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest: Request = chain.request()
val httpUrl: HttpUrl = originalRequest.url
val builder: Request.Builder = originalRequest.newBuilder()
val envList: List<String> = originalRequest.headers("Host-Env")
if (envList.isNotEmpty()) {
builder.removeHeader("Host-Env")
val env = envList[0]
var baseURL: HttpUrl? = null
//根据头信息中配置的value,来匹配新的base_url地址
if ("ANDROID" == env) {
baseURL = "https://developer.android.com/".toHttpUrlOrNull()
}
if (baseURL != null) {
//重建新的HttpUrl,需要重新设置的url部分
val newHttpUrl: HttpUrl = httpUrl.newBuilder()
.scheme(baseURL.scheme) //http协议如:http或者https
.host(baseURL.host) //主机地址
.port(baseURL.port) //端口
.build()
//获取处理后的新newRequest
val newRequest: Request = builder.url(newHttpUrl).build()
return chain.proceed(newRequest)
}
}
return chain.proceed(originalRequest)
}
}

创建OkHttpClient对象,并添加域名切换拦截器HostInterceptor

1
2
3
4
5
6
val okHttpClient = OkHttpClient.Builder()
.connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
.writeTimeout(writeTimeout, TimeUnit.SECONDS)
.addInterceptor(HostInterceptor.create())
.build()

正常使用retrofit对象生成ApiService,请求服务走到拦截器并切换BaseUrl

1
2
3
4
5
6
@Header("Host-Env", "ANDROID")
@GET("login")
fun login(
@Query("mobile") phone: String,
@Query("code") code: String
): Call<ResponseBody>

PS:通过自定义Header标签,可以根据标签的类型仅动态切换指定类型的域名

特别感谢

特别感谢以下博文

解决Retrofit多BaseUrl及运行时动态改变BaseUrl:https://www.jianshu.com/p/2919bdb8d09a

作者

Dench

发布于

2023-10-17

更新于

2023-10-17

许可协议

CC BY-NC-SA 4.0

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×