Как изменить базовый URL API во время выполнения (Retrofit, Android, Java)? - PullRequest
0 голосов
/ 30 октября 2018

Мне нужно изменить базовый URL во время выполнения. У меня есть кнопка входа в систему и когда время нажатия кнопки входа в систему меня называют мой логин API как показано ниже:

логин api = http://192.168.0.61/api/authenticate

API_BASE_URL = http://192.168.0.61/api/

когда я получаю ответ об успешном завершении первого API, я получаю URL-адрес клиентского сервера для изменения baseUrl.

CompanyUrlConfigEntity companyUrlConfigEntity = response.body (); как показано ниже:

String clientUrl = companyUrlConfigEntity. getBaseUrl ();

                            clientUrl = http://192.168.0.238/api/

В этом проекте в основном для клиента или компании. Так что у них есть собственный сервер. Каждая компания использует более 20 API-интерфейсов. Поэтому мне нужно изменить базовый URL.

Я также проверил ссылку ниже для изменения базового URL:

https://futurestud.io/tutorials/retrofit-2-how-to-change-api-base-url-at-runtime-2

и измененный код вот так

public static void changeApiBaseUrl(String newApiBaseUrl) {
    API_BASE_URL = newApiBaseUrl;

    builder = new Retrofit.Builder()
            .baseUrl(API_BASE_URL)
                    .addConverterFactory(new NullOnEmptyConverterFactory())
                    .addConverterFactory(ScalarsConverterFactory.create())
                    .addConverterFactory(GsonConverterFactory.create(new Gson()));
}

когда я отлаживаю и проверяю свой baseUrl, тогда он отображается правильно, как показано ниже:

API_BASE_URL =  http://192.168.0.238/api/



But when i call my customer api it shows the my first base url calling,
the url not changed.

expected customer api : http://192.168.0.238/api/customers
reality customer api : http://192.168.0.61/api/customers


I am also checked below link :

https://futurestud.io/tutorials/retrofit-2-how-to-use-dynamic-urls-for-requests

thats working , But each api need to pass fullPath url with each api like below:
@GET
public Call<ResponseBody> profilePicture(@Url String url);

But using this method , each api calling place i need to attach full path of url.

There is any other options? Please help me.

ServiceGenerator.class

    public class ServiceGenerator {

  public static String API_BASE_URL = "http://192.168.0.61/api/";

   private static Retrofit retrofit;

 private static OkHttpClient.Builder httpClient = new 
 OkHttpClient.Builder();

private static Retrofit.Builder builder =
        new Retrofit.Builder()
                .baseUrl(API_BASE_URL)
                .addConverterFactory(new NullOnEmptyConverterFactory())
                .addConverterFactory(ScalarsConverterFactory.create())
                .addConverterFactory(GsonConverterFactory.create(new 
       Gson()));

   private ServiceGenerator() {

   }

 public static void changeApiBaseUrl(String newApiBaseUrl) {
         API_BASE_URL = newApiBaseUrl;

       builder = new Retrofit.Builder()
            .baseUrl(API_BASE_URL)
                    .addConverterFactory(new NullOnEmptyConverterFactory())
                    .addConverterFactory(ScalarsConverterFactory.create())
                    .addConverterFactory(GsonConverterFactory.create(new Gson()));


}   

 public static Retrofit retrofit() {
    return retrofit;
}
public static <S> S createService(Class<S> serviceClass) {
    return createService(serviceClass, null, null);
}

  public static <S> S createService(Class<S> serviceClass,
                                  final String authToken,
                                  final ProgressListener progressListener) {
    if (authToken != null) {
           httpClient.addInterceptor(new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request original = chain.request();

                final String headerValue = AUTHORIZATION_TYPE + authToken;
                Request request = original.newBuilder()
                        .header(AUTHORIZATION_HEADER_KEY, headerValue)
                        .method(original.method(), original.body())
                        .build();
                return chain.proceed(request);
            }
        });
    }

    addResponseProgressListener(progressListener);

    if (BuildConfig.DEBUG) {
        HttpLoggingInterceptor httpLoggingInterceptor = new 
        HttpLoggingInterceptor();
        httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        httpClient.addInterceptor(httpLoggingInterceptor);
    }


    if (authToken != null) {
        if (picasso == null) {
            setUpPicasso(authToken);
        }
    }


    OkHttpClient client = httpClient.build();
    httpClient.connectTimeout(15, TimeUnit.SECONDS);
    httpClient.readTimeout(2, TimeUnit.MINUTES);
    httpClient.writeTimeout(2, TimeUnit.MINUTES);
    retrofit = builder.client(client).build();

    return retrofit.create(serviceClass);
}
}

LoginFragment.java

@OnClick(R.id.bt_login)
void onLogin() {

    checkValidityOfUser();

}

private void checkValidityOfUser() {
    final Login login = getLoginCredentials();

    Call<CompanyUrlConfigEntity> callCheckValidity = dataProcessController.
            getApiClient().
            checkValidityOfUsers(login.getUsername());

    callCheckValidity.enqueue(new Callback<CompanyUrlConfigEntity>() {
        @Override
        public void onResponse(Call<CompanyUrlConfigEntity> call,
                               Response<CompanyUrlConfigEntity> response) {


            if (response.code() == 200) {

                CompanyUrlConfigEntity companyUrlConfigEntity = response.body();

                boolean status = companyUrlConfigEntity.isValidUser();

                if (status) {

                    String baseUrls = companyUrlConfigEntity.
                            getBaseUrl();
                    baseUrls = baseUrls + "/api/";
                    ServiceGenerator.changeApiBaseUrl(baseUrls);
                    logins();
                } else {

                    ToastHelper.show("please contact  admin");

                }


            } else {

                ToastHelper.show("" + response.code() + response.message());

            }

        }

        @Override
        public void onFailure(Call<CompanyUrlConfigEntity> call, Throwable t) {

            ToastHelper.show("please contact  admin");
        }
    });
}


private void logins() {
    login = getLoginCredentials();
    Call<Void> callLogin = dataProcessController.
            getApiClient().
            login(login);

    callLogin.enqueue(new Callback<Void>() {
        @Override
        public void onResponse(Call<Void> call, Response<Void> response) {

            if (response.code() == 200) {

            } else if (response.code() == 401) {

            }
        }

        @Override
        public void onFailure(Call<Void> call, Throwable t) {

        }
    });
}

Ответы [ 2 ]

0 голосов
/ 31 октября 2018

https://segunfamisa.com/posts/firebase-remote-config

Вы должны следовать концепции удаленной конфигурации Firebase. Здесь вам не нужно хранить базовый URL в исходном коде, он будет получен из значений конфигурации firebase, которые хранятся на сервере firebase.

// fetch
mRemoteConfig.fetch(3000)
        .addOnCompleteListener(this, new OnCompleteListener<Void>() {
            @Override
            public void onComplete(Task<Void> task) {
                if (task.isSuccessful()) {
                    // update your base url here. 
                } else {
                    //task failed
                }
            }
        });
0 голосов
/ 31 октября 2018

Основываясь на ваших комментариях, я бы сказал, что вы правильно изменяете URL-адрес API вашего компоновщика, но при втором вызове все еще используется экземпляр службы, где URL-адрес не изменился.

Чтобы объяснить немного больше, из того, что я понимаю, вот как все выполняется:

  • когда создается фрагмент, apiClient создается и указывает на первый URL
  • с dataProcessController.getApiClient() при первом вызове вы получаете службу, которая указывает на первый URL, а затем выполняете вызов.
  • когда вызов успешен, вы читаете новый URL из результата и обновляете ServiceGenerator этим новым URL. Затем вы выполняете метод logins().
  • и в этом методе вы вызываете dataProcessController.getApiClient() и выполняете второй вызов с ним. Однако, поскольку вы никогда не переделываете apiClient = ServiceGenerator.createService(ApiClient.class);, экземпляр apiClient, который вы получаете, все еще указывает на первый URL, потому что он не был уведомлен об изменении URL.

Я бы попытался изменить метод getApiClient() в вашем DataProcessController классе на что-то вроде этого:

public ApiClient getApiClient() {
    apiClient =  ServiceGenerator.createService(ApiClient.class);
    return apiClient;
}

и посмотрите, будет ли это лучше.

Или, если вы не хотите восстанавливать службу внутри этой функции, вы также можете сделать что-то вроде этого:

public class DataProcessController { 
    private ApiClient apiClient = null; 

    private DataProcessController() { 
        regenerateClient(); 
    }

    public ApiClient getApiClient() { return apiClient; }

    // add this to regenerate the client whenever url changes
    public void regenerateClient() {
        apiClient = ServiceGenerator.createService(ApiClient.class);
    }
}

затем, каждый раз, когда вы меняете URL, делайте это:

ServiceGenerator.changeApiBaseUrl(baseUrls);
dataProcessController.regenerateClient();

и вы должны получить клиента, который указывает на правильный URL-адрес каждый раз, когда вы делаете dataProcessController.getApiClient()

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...