Модернізація Android Параметризована @Headers


85

Я використовую OAuth, і мені потрібно вставити маркер OAuth у свій заголовок кожного разу, коли я роблю запит. Я бачу @Headerанотацію, але чи є спосіб зробити її параметризованою, щоб я міг перейти під час виконання?

Ось така концепція

@Header({Authorization:'OAuth {var}', api_version={var} })

Чи можете ви передати їх під час виконання?

@GET("/users")
void getUsers(
    @Header("Authorization") String auth, 
    @Header("X-Api-Version") String version, 
    Callback<User> callback
)

Ви коли-небудь це зрозуміли? Мені також потрібно передати знак у заголовку
— TheSociableme

Я також шукаю рішення цього, з документації це звучить як @Headers () анотація методу додає поля до заголовка по одному, але підтримує лише літерали. А @Header ("параметр") Анотація параметра рядка рядка замінює заголовок наданим значенням.
— nana

2
Те саме тут, не вдалося з’ясувати, як обробляти сеанси при використанні модернізації.
— FRR

Нам не потрібно було передавати всі предмети, сама модернізація обробляє всі. Будь ласка, перевірте моє посилання на відповідь у StackOverflow.
— Субін Бабу

Відповіді:


98

Окрім використання параметра @Header, я волів би використовувати RequestInterceptor для оновлення всього вашого запиту, не змінюючи інтерфейс. Використовуючи щось на зразок:

RestAdapter.Builder builder = new RestAdapter.Builder()
    .setRequestInterceptor(new RequestInterceptor() {
        @Override
        public void intercept(RequestFacade request) {
            request.addHeader("Accept", "application/json;versions=1");
            if (isUserLoggedIn()) {
                request.addHeader("Authorization", getToken());
            }                    
        }
    });

p / s: Якщо ви використовуєте Retrofit2, вам слід використовувати InterceptorзамістьRequestInterceptor

Оскільки RequestInterceptorбільше не доступний у Retrofit 2.0


3
Це не пов’язано безпосередньо, але якщо вам потрібно отримати значення з об’єкта запиту, щоб створити заголовок авторизації, вам потрібно буде розширити ApacheClient і виконати копію об’єкта Request (List <Header> headers = ... ; Request requestNew = новий Request (request.getMethod (), request.getUrl (), заголовки, request.getBody ()); request = requestNew).

1
Це трюк, який псує закодований, краще використовуйте відповідь @ nana
— Іван Фазанюк

1
RestAdapterзалежить від Retrofit1, у Retrofit2 це Retrofit. Я збираюся використовувати Retrofit2, тож не виникає проблем, якщо використовувати RequestInterceptorкод вище?
— Huy Tower

55

Так, ви можете пройти їх під час виконання. Насправді, майже так само, як ви це ввели. Це буде у вашому класі інтерфейсу API, який називається say SecretApiInterface.java

public interface SecretApiInterface {

    @GET("/secret_things")
    SecretThing.List getSecretThings(@Header("Authorization") String token)

}

Потім ви передаєте параметри цьому інтерфейсу із вашого запиту, щось подібне до цих рядків: (цей файл буде, наприклад, SecretThingRequest.java )

public class SecretThingRequest extends RetrofitSpiceRequest<SecretThing.List, SecretApiInteface>{

    private String token;

    public SecretThingRequest(String token) {
        super(SecretThing.List.class, SecretApiInterface.class);
        this.token = token;
    }

    @Override
    public SecretThing.List loadDataFromNetwork() {
        SecretApiInterface service = getService();
        return service.getSecretThings(Somehow.Magically.getToken());
    }
}

Де Somehow.Magically.getToken()виклик методу, який повертає маркер, від вас залежить, де і як ви його визначите.

Звичайно, ви можете мати кілька @Header("Blah") String blahанотацій у реалізації інтерфейсу, як у вашому випадку!

Мене це теж заплутало, в документації чітко сказано, що він замінює заголовок, але НЕ !
Фактично це додано як із @Headers("hardcoded_string_of_liited_use")анотацією

Сподіваюся, це допомагає;)


1
У документах я виявив, що він не замінює існуючий заголовок: "Зверніть увагу, що заголовки не перезаписують один одного". Перевірте square.github.io/retrofit та "Маніпуляцію заголовком"
— Amio.io

37

Прийнята відповідь стосується старої версії модернізації. Для майбутніх глядачів спосіб зробити це за допомогою Retrofit2.0 - це користувальницький клієнт OkHttp:

OkHttpClient httpClient = new OkHttpClient.Builder()
  .addInterceptor(new Interceptor() {
    @Override
    public Response intercept(Chain chain) throws IOException {
      Builder ongoing = chain.request().newBuilder();
      ongoing.addHeader("Accept", "application/json;versions=1");
      if (isUserLoggedIn()) {
        ongoing.addHeader("Authorization", getToken());
      }
      return chain.proceed(ongoing.build());
    }
  })
  .build();

Retrofit retrofit = new Retrofit.Builder()
  // ... extra config
  .client(httpClient)
  .build();

Сподіваюся, це комусь допомагає. :)


5
У загальному застосуванні з dagger2, retrofit2 буде одностороннім, тому httpclient не створюється кожного разу. у такому випадку isUserLoggedIn () не має сенсу, я прав? Єдине рішення, яке я бачу в даний час, - це примусити реініціалізацію retrofit2 при зміні статусу входу користувача, щоб відповідний заголовок був доданий або видалений із запиту .. або є якесь очевидне рішення, яке я зараз не можу побачити? Дякую.
— bajicdusko

2
@bajicdusko це мій точно такий самий коннундрум. Ви знайшли рішення? Це здається таким марнотратним і дивним, що попередня версія була більш ефективною.
— deed02392

@ deed02392 Ви можете встановити композит, Interceptorдля якого ви можете встановити або скинути перехоплювач пізніше. Однак я б стверджував, що наявність модернізації як синглтона може свідчити про ранню оптимізацію. Немає накладних витрат на створення нового примірника: github.com/square/retrofit/blob/master/retrofit/src/main/java/…
— pablisco

Я насправді не глибоко про це думав. У мене є клас ApiFactory, який також ініціалізується за допомогою dagger2, і він відповідає за ініціалізацію модернізації. Я виставив один загальнодоступний метод в ApiFactory, який змушує реініціалізувати екземпляр модернізації, коли це потрібно, тому він досить простий. Я можу робити це неправильно, але це зробило роботу, і я використовую його лише для заголовка авторизації, тому він використовується під час входу або виходу користувача. Інший варіант - використовувати анотацію @Header всередині визначення кінцевої точки, що для мене не було прийнятним. Я повинен встановлювати його для кожної кінцевої точки, що не є практичним.
— bajicdusko

@pablisco Ах, наскільки я розумію, ви не змогли додати або видалити Interceptors, коли створили екземпляр Retrofit2.
— deed02392

7

Модернізація 2.3.0

OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
    okHttpClientBuilder
            .addInterceptor(new Interceptor() {
                @Override
                public okhttp3.Response intercept(Chain chain) throws IOException {
                    Request request = chain.request();
                    Request.Builder newRequest = request.newBuilder().header("Authorization", accessToken);
                    return chain.proceed(newRequest.build());
                }
            });

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(GithubService.BASE_URL)
            .client(okHttpClientBuilder.build())
            .addConverterFactory(GsonConverterFactory.create())
            .build();

Я використовую це для підключення до GitHub.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.