Подтвердить что ты не робот

Как динамически устанавливать заголовки в Retrofit (Android)

Я использую API, который использует схему авторизации, для которой требуется установить специальный заголовок "X-Authorization" для проверки подлинности запроса. Например, эта настройка Retrofit отлично работает для пользователя, чей токен аутентификации abc123:

@Headers("X-Authorization: abc123")
@GET("/posts")
Observable<List<Post>> get_posts();

Я кэширую токен пользователя X-Authorization, поэтому у меня есть доступ к нему, однако я не могу просто его отбросить в объявлении @Headers.

@Headers("X-Authorization: " + token)
@GET("/posts")
Observable<List<Post>> get_posts();

Я получаю ошибку компиляции здесь: Error:(41, 34) error: element value must be a constant expression

Любые идеи о том, как я мог обойти это?

4b9b3361

Ответ 1

Начиная с Retrofit 2.0 у вас есть два варианта


1) Используя OkHttp 2. 2+ используйте Interceptor

На уровне Http у вас есть больший контроль над запросом, поэтому вы можете делать такие вещи, как применение заголовков только к конкретному запросу, сделанному к определенной конечной точке, и так далее.

public class MyOkHttpInterceptor implements Interceptor {

@Override
public Response intercept(Chain chain) throws IOException {
    Request originalRequest = chain.request();
    if (!"/posts".contains(originalRequest.url()) ) {
        return chain.proceed(originalRequest);
    }

    String token = // get token logic 

    Request newRequest = originalRequest.newBuilder()
        .header("X-Authorization", token)
        .build();

    return chain.proceed(newRequest);
}

[...]

OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.networkInterceptors().add(new MyOkHttpInterceptor());
OkClient okClient = new OkClient(okHttpClient);
YourApi api = new RestAdapter.Builder()
            .setEndpoint(url)
            .setClient(okClient)
            .build()
            .create(YourApi.class);

Редактировать: Добавление комментария @JakeWarthon в качестве другого параметра, который также является действительным.

2) Поместите @Header в параметр метода и передайте его как значение при вызове.

Из документов:

// Replaces the header with the the value of its target.
@GET("/")
void foo(@Header("Accept-Language") String lang, Callback<Response> cb);

Параметры заголовка могут быть нулевыми, что исключит их из запроса. Передача списка или массива приведет к появлению заголовка для каждого ненулевого элемента.

Примечание. Заголовки не перезаписывают друг друга. Все заголовки с одинаковым именем будут включены в запрос.


РЕДАКТИРОВАТЬ: эта опция не должна рассматриваться как Retrofit 2. * исключена поддержка перехватчиков.

3) Модификация пользователя RequestInterceptor

Из документов: Перехватывайте каждый запрос перед его выполнением, чтобы добавить дополнительные данные.

Вы могли бы сделать что-то вроде

public class MyRetrofitInterceptor implements RequestInterceptor {

@Override
public void intercept(RequestFacade req) {
    String token = // get token logic 
    if (token != null) {
        req.addHeader("X-Authorization", token);
    }
}

[...]

YourApi api = new RestAdapter.Builder()
            .setEndpoint(url)
            .setRequestInterceptor(new MyRetrofitInterceptor())
            .build()
            .create(YourApi.class);

"Проблема" в этом подходе заключается в том, что перехватчик будет выполняться на всех конечных точках, как это установлено на уровне RestAdapter, а не для каждой конечной точки. Кроме того, RequestFacade не предоставляет много информации о запросе, поэтому нет шансов добавить много логики вокруг него.

Ответ 2

Передача заголовка в параметре будет полезной. Посмотрите на следующий код;

 @GET("/posts")
Observable<JsonElement> getDataFromService(
        @HeaderMap Map<String, String> headers,
        @QueryMap HashMap<String, Object> queryParams
);

        hashMap1.put("Authorization", token);
    return ApiService.getAPI_test().getDataFromService(hashMap1, url, hashMap)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.io());

Ответ 4

Динамический заголовок в модификации 2

Я слишком много пытался добавить динамический заголовок в Retrofit 2.

Я прошел через очень много блогов и StackOver потока. Каждый показал пример с Interceptor.

И это не мудро, просто для одного вызова API нам нужно проделать такую большую работу.

Вам просто нужно добавить @HeaderMap в качестве аргумента веселья. Я сделал очень простым способом:

В котлине

    val headers = HashMap<String, String>()
    headers["KEY_AUTHORIZATION"] = "paste AUTHORIZATION value here"
    headers["KEY_TOKEN"] = "paste TOKEN value here"

    val jsonObject= JsonObject()

I am passing here header and other data also
Calling of fun:-

postEvent(headers,jsonObject)

API Declaration 

    @POST("/v1/post_data")
    fun postEvent(@HeaderMap headers: Map<String, String>, @Body jsonObject: JsonObject): Call<JsonObject>

API Declaration with RxAndroid

    @POST("/v1/post_data")
    fun postEvent(@HeaderMap headers: Map<String, String>, @Body jsonObject: JsonObject): Single<JsonObject>

Второй аргумент здесь у меня есть JsonObject. Вы можете заменить все, что вам нужно передать, или вы можете удалить это тоже.

На яве

 HashMap<String, String> headers = new HashMap<String, String>();
    headers.put("KEY_AUTHORIZATION","paste AUTHORIZATION value here");
    headers.put("KEY_TOKEN", "paste TOKEN value here");

    JsonObject jsonObject= new JsonObject();

I am passing here header and other data also

Calling of fun:-
postEvent(headers,jsonObject);

    API Declaration 
    @POST("/v1/post_data")
    Call<JsonObject> postEvent(@HeaderMap Map<String, String> headers, @Body JsonObject jsonObject);

API Declaration with RxAndroid

    @POST("/v1/post_data")
    Single<JsonObject> postEvent(@HeaderMap Map<String, String> headers, @Body JsonObject jsonObject);

Второй аргумент здесь у меня есть JsonObject. Вы можете заменить все, что вам нужно передать, или вы можете удалить это тоже.