Модернізація 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.