Actualizar – Cambiar BaseUrl

5 minutos de lectura

avatar de usuario
Subby

Tengo un escenario en el que tengo que llamar a una API con la misma URL base, por ejemplo www.myAPI.com pero con otro diferente baseUrl.

Tengo una instancia de Retrofit 2 que se construye a través de un Builder:

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

los FlavourConstants.BASE_URL Se ve como esto:

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

Para algunos WebRequestsdebo llamar a la misma API pero en otras, debo llamarla desde una completamente diferente BaseUrl. ¿Cómo cambio el Retrofit instancia para, por lo tanto, apuntar a una URL diferente durante el tiempo de ejecución?

los Retrofit instancia no tiene un .setBaseUrl o setter o algo similar ya que está construido a través de un Builder.

¿Algunas ideas?

  • como ya has mencionado, la Retrofit instancia es algo inmutable (algo así como para lo que están destinados los constructores). Por lo tanto, deberá crear otra instancia para la otra URL que desee configurar.

    – preguntas

    6 de agosto de 2016 a las 16:58

  • stackoverflow.com/a/63076030/7511020 si no está usando dagger2, solo vea el paso 1 y agregue su interceptor en el objeto HttpClient Builder

    – Zeeshan Ajtar

    24 de julio de 2020 a las 14:55

avatar de usuario
Nir Duan

Por suerte, Retrofit tiene una solución simple para eso:

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

los url La cadena debe especificar la URL completa que desea usar.

  • Esto solo funciona para GET métodos y no para HTTP métodos tales como @POST. He resuelto el problema y publicaré una respuesta una vez que haya verificado que funciona.

    – Subby

    07/08/2016 a las 17:10

  • @Subby, ¿verificaste que funcionó? ¿Dónde está tu respuesta?

    – Guerra de neón

    2 de octubre de 2018 a las 1:13

  • Esta no es la solución al problema original, no cambia la URL base (y también contamina la API). Mantiene la URL base original, pero le permite cambiar completamente el punto final para una llamada en particular; es una solución alternativa, pero no resuelve el problema en cuestión. (y sí, lo acabo de probar, funciona)

    – milosmns

    3 mayo 2019 a las 14:15


  • @Subby por qué esta respuesta no funciona con @POST?

    – DEVS bit a bit

    20 de marzo a las 7:44

Adaptación 2.4, MAYO DE 2019

Dos soluciones simples para esta molestia son:

  1. Codifique la nueva URL, mientras deja la URL base como está:

    @GET("http://example.com/api/")
    Call<JSONObject> callMethodName();
    
  2. Pase la nueva URL como argumento, mientras deja la URL base como está:

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

NB: estos métodos funcionan para GET o POST. Sin embargo, esta solución solo es eficiente si solo necesita usar una excepción de una o dos URL diferentes a su URL base. De lo contrario, las cosas pueden complicarse un poco en términos de limpieza del código.

Si su proyecto exige URL base generadas completamente dinámicamente, entonces puede comenzar a leer este.

avatar de usuario
Vlad

También hay un truco de este tipo en Kotlin al definir la URL base

p.ej

@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

No funciona. Lanza:

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

La única manera es sugerida por 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()
        )
    }
}

avatar de usuario
fileo99

La forma más fácil (pero no la más eficiente) de cambiar la URL base de Retrofit2 en tiempo de ejecución es reconstruir la instancia de actualización con la nueva 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);

Alternativamente, si está utilizando OkHttp con Retrofit, puede agregar un interceptor OkHttp como Éste al construir su cliente OkHttp:

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

avatar de usuario
cuba

Acabo de usar la siguiente función cuando enfrenté este problema. pero estaba apurado y creo que tengo que usar otro y estaba usando “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;
    }

[Update]

he encontrado esto Enlace eso explica el @Url que se puede enviar como parámetro y creo que es más profesional que mi solución anterior. Encuentre a continuación el escenario:

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

Y debajo está el método en la clase que proporciona el objeto de actualización

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

Luego puede llamar al método de la siguiente manera:

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

avatar de usuario
vetón neziri

Deberías usar un interceptor así:

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

avatar de usuario
Catluc

Ok, si no recuerdo mal, los documentos de Retrofit dicen que puede apuntar a otra URL si simplemente agrega en su servicio de interfaz la URL completa de ws, que es diferente de BASE_URL en Retrofit Builder. Un ejemplo…

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

¿Ha sido útil esta solución?