改造 - 改变BaseUrl

时间:2016-08-06 15:07:55

标签: android retrofit

我有一个场景,我必须使用相同的BaseUrl调用API,例如www.myAPI.combaseUrl不同。

我有一个Retrofit 2的实例,它是通过Builder

构建的

return new Retrofit.Builder().baseUrl(FlavourConstants.BASE_URL).addConverterFactory(GsonConverterFactory.create(gson)).client(okHttpClient).build();

FlavourConstants.BASE_URL看起来像这样:

public static final String BASE_URL = "http://myApi.development:5000/api/v1/";

对于某些WebRequests,我必须调用相同的API,但在其他API中,我必须从完全不同的BaseUrl调用它。如何在运行时更改Retrofit实例以指向不同的URL?

Retrofit实例没有.setBaseUrlsetter或与Builder构建的类似内容。

有什么想法吗?

10 个答案:

答案 0 :(得分:16)

幸运的是,Retrofit有一个简单的解决方案:

public interface UserManager {  
    @GET
    public Call<ResponseBody> userName(@Url String url);
}

url字符串应指定您要使用的完整网址。

答案 1 :(得分:4)

当我遇到这个问题时,我只是使用了以下功能。但我很着急,我相信我必须使用另一个,我正在使用“retrofit2:retrofit:2.0.2”

public static Retrofit getClient(String baseURL) {
        if (retrofit == null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl(baseURL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        } else {
            if (!retrofit.baseUrl().equals(baseURL)) {
                retrofit = new Retrofit.Builder()
                        .baseUrl(baseURL)
                        .addConverterFactory(GsonConverterFactory.create())
                        .build();
            }
        }
        return retrofit;
    }

[<强>更新] 我发现这个link解释了可以作为参数发送的@Url,我相信它比我以前的解决方案更专业。 请在下面找到方案:

    interface APIService{
         @POST
         Call<AuthenticationResponse> login(@Url String loginUrl,[other parameters])
    }

以下是类中提供改造对象的方法

public static Retrofit getClient() {
    if (retrofit==null) {
        retrofit = new Retrofit.Builder()
                .baseUrl("http://baseurl.com") // example url
                .addConverterFactory(GsonConverterFactory.create())
                .build();
    }
    return retrofit;
}

然后你可以调用如下方法:

    APIInterface apiInterface = ApiClient.getClient2().create(ApiInterface.class);
    apiInterface.login("http://tempURL.com").enqueue(......);

答案 2 :(得分:3)

在运行时更改Retrofit2基本URL的最简单(但不是最高效)方法是使用新网址重建改进实例:

private Retrofit retrofitInstance = Retrofit.Builder().baseUrl(FlavourConstants.BASE_URL).addConverterFactory(GsonConverterFactory.create(gson)).client(okHttpClient).build();

public void setNewBaseUrl(String url) {
   retrofitInstance = new Retrofit.Builder()
      .baseUrl(url)
      .addConverterFactory(GsonConverterFactory.create(gson))
      .client(okHttpClient).build();
}

...
retrofitInstance.create(ApiService.class);

或者,如果你使用OkHttp和Retrofit,你可以在构建你的OkHttp客户端时添加像this one这样的OkHttp拦截器:

HostSelectionInterceptor hostInterceptor = new HostSelectionInterceptor();
hostInterceptor.setHost(newBaseUrl);
return new OkHttpClient.Builder()
    .addInterceptor(hostInterceptor)
    .build();

答案 3 :(得分:3)

在定义基本网址时,科特林也有这样的漏洞

例如

@FormUrlEncoded
@Headers("Accept: application/json")
@POST
suspend fun login(
    baseUrl: String,
    @Field("login") login: String,
    @Field("password") password: String
    @Url url: String = "$baseUrl/auth"
): ResponseAuth

它不起作用。抛出:

java.lang.IllegalArgumentException: No Retrofit annotation found. (parameter #1)

Jake Wharton https://github.com/square/retrofit/issues/2161#issuecomment-274204152

提出了唯一的方法
Retrofit.Builder()
    .baseUrl("https://localhost/")
    .create(ServerApi::class.java)
class DomainInterceptor : Interceptor {

    @Throws(Exception::class)
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        return chain.proceed(
            request.newBuilder()
                .url(
                    request.url.toString()
                        .replace("localhost", "yourdomain.com:443")
                        .toHttpUrlOrNull() ?: request.url
                )
                .build()
        )
    }
}

答案 4 :(得分:1)

好的,如果我不记得错了Retrofit的文档说你可以指向另一个URL,如果你只是简单地在你的界面servicse中添加ws的完整url,这与Retrofit Builder中的BASE_URL不同。一个例子......

public interface UserManager {  
    @GET("put here ur entire url of the service")
    public Call<ResponseBody> getSomeStuff();
}

答案 5 :(得分:1)

以防万一您想通过获取 Retrofit 的实例来使用 Koin Framework 更改基本 URL:

fun updateApiUrl(url: String) {
    // This is the "trick"
    var retrofit: Retrofit = getKoin().get()

    Log.e("OLD URL", retrofit.baseUrl().toString())

    retrofit = retrofit.newBuilder()
        .baseUrl(url)
        .client(getKoin().get())
        .addConverterFactory(GsonConverterFactory.create())
        .build()

    Log.e("NEW URL", retrofit.baseUrl().toString())
}

如果您有任何疑问,我已经上传了源代码:Just click here :)

答案 6 :(得分:0)

解决方案是拥有两个不同的改造实例,一个用于您的FLAVORED基本URL,另一个用于另一个基本URL。

所以只需定义两个函数:

     public Retrofit getFlavouredInstance() {
        return new Retrofit.Builder().baseUrl(FlavourConstants.BASE_URL).addConverterFactory(GsonConverterFactory.create(gson)).client(okHttpClient).build();
     }

     public Retrofit getOtherBaseUrl() {
        return Retrofit.Builder().baseUrl(OTHER_BASE_URL).addConverterFactory(GsonConverterFactory.create(gson)).client(okHttpClient).build();
     }

然后你必须使用正确的。

答案 7 :(得分:0)

Retrofit 2.4,2019年5月

解决这个麻烦的两个简单解决方案是:

  1. 对新URL进行硬编码,同时保留基本URL:

    @GET("http://example.com/api/")
    Call<JSONObject> callMethodName();
    
  2. 将新URL作为参数传递,同时保留基本URL:

    @GET
    Call<JSONObject> callMethodName(@Url String url);
    

N.B:这些方法适用于GET或POST。但是,仅当您需要使用一个或两个不同于基本URL的URL例外时,此解决方案才有效。否则,在代码整洁方面,事情可能会变得有些混乱。

如果您的项目需要完全动态生成的基本URL,则可以开始阅读this

答案 8 :(得分:0)

请尝试以下代码:

private void modify(String url) throws Exception {

    Class mClass = retrofit.getClass();


    Field privateField = mClass.getDeclaredField("baseUrl");

    if (privateField != null) {
        privateField.setAccessible(true);

        System.out.println("Before Modify:MSG = " + retrofit.baseUrl().url().getHost());


        privateField.set(retrofit,  HttpUrl.parse(url));
        System.out.println("After Modify:MSG = " + retrofit.baseUrl().url().getHost());
    }
}

答案 9 :(得分:0)

你应该像这样使用拦截器:

class HostSelectionInterceptor: Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        apiHost?.let { host ->
            val request = chain.request()
            val newUrl = request.url.newBuilder().host(host).build()
            val newRequest = request.newBuilder().url(newUrl).build()
            return chain.proceed(newRequest)
        }
        throw IOException("Unknown Server")
    }
}

You just need to change at runtime the apiHost variable (var apiHost = "example.com"). Then add this interceptor to OkHttpClient builder:

val okHttpClient = OkHttpClient.Builder()
    .addInterceptor(HostSelectionInterceptor())
    .build()