【问题标题】:Retrofit - Change BaseUrl改造 - 更改 BaseUrl
【发布时间】:2016-12-12 20:10:22
【问题描述】:

我有一个场景,我必须使用相同的基本 URL 调用 API,例如www.myAPI.com 但使用不同的baseUrl

我有一个 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,但对于其他人,我必须从完全不同的BaseUrl 调用它。如何在运行时更改 Retrofit 实例以指向不同的 URL?

Retrofit 实例没有.setBaseUrlsetter 或任何类似的东西,因为它是通过Builder 构建的。

有什么想法吗?

【问题讨论】:

  • 正如您已经提到的,Retrofit 实例是不可变的(这是 Builders 的用途)。因此,您需要为要设置的其他 URL 创建另一个实例。
  • stackoverflow.com/a/63076030/7511020 如果您没有使用 dagger2,那么只需查看 step1 并将您的拦截器添加到 HttpClient Builder 对象中

标签: android retrofit


【解决方案1】:

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

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

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

【讨论】:

  • 这仅适用于GET 方法,不适用于HTTP 方法,例如@POST。我已经解决了这个问题,一旦我确认它有效,我会发布答案。
  • @Subby 你确认它有效吗?你的答案在哪里?
  • 这不是原始问题的解决方案,它不会更改基本 URL(并且还会污染 API)。它保留原始的基本 URL,但允许您完全更改一个特定调用的端点 - 这是一种解决方法,但它不能解决手头的问题。 (是的,我刚试过,它有效)
【解决方案2】:

改造 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);
    

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

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

【讨论】:

    【解决方案3】:

    在 Kotlin 中定义基本 url 时也有这样的 hack

    例如

    @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
                    )
                    // OR
                    //.url(HttpUrl.parse(request.url().toString().replace("localhost", "yourdomain.com:443")) ?: request.url())
                    .build()
            )
        }
    }
    

    【讨论】:

    • 非常感谢,先生,您的解决方案对我很有帮助。
    【解决方案4】:

    在运行时更改 Retrofit2 基本 URL 的最简单(但不是最高效)的方法是使用新 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);
    

    或者,如果您使用带有 Retrofit 的 OkHttp,您可以在构建 OkHttp 客户端时添加一个 OkHttp 拦截器,例如 this one

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

    【讨论】:

    • 是的,拦截器似乎是最干净的方法。
    【解决方案5】:

    当我遇到这个问题时,我只是使用了以下功能。但我很着急,我相信我必须使用另一个,我正在使用“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(......);
    

    【讨论】:

    • 这个答案拯救了我的一天,它对我有用,谢谢。
    【解决方案6】:

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

    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()
    

    【讨论】:

    • 这是最好的答案。它运作良好。谢谢!
    【解决方案7】:

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

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

    【讨论】:

      【解决方案8】:

      以防万一您想通过获取 Retrofit 的实例来使用 Koin 框架更改基本 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 :)

      【讨论】:

        【解决方案9】:

        一种解决方案是有两个不同的改造实例,一个用于您的 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();
             }
        

        然后你只需要使用正确的。

        【讨论】:

          【解决方案10】:

          请尝试以下代码:

          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());
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2021-09-27
            • 1970-01-01
            • 2021-08-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多