web-dev-qa-db-ja.com

Retrofitでヘッダーを動的に設定する方法(Android)

要求を認証するために特別な「X-Authorization」ヘッダーを設定する必要がある認証スキームを使用するAPIを使用しています。たとえば、この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

これをどのように回避できるかについてのアイデアはありますか?

49
johncorser

Retrofit 2.0以降、2つのオプションがあります


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

Edit@ JakeWarthon コメントを別のオプションとして追加することも有効。

2)メソッドパラメータに @ Header を設定し、呼び出し時に値として渡します。

docsから

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

ヘッダーパラメータはnullの場合があり、リクエストから省略されます。リストまたは配列を渡すと、null以外の各アイテムのヘッダーが生成されます。

注:ヘッダーは相互に上書きしません。同じ名前のすべてのヘッダーがリクエストに含まれます。


EDIT:このオプションは、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はリクエストに関する多くの情報を公開しないため、ロジックを追加する機会はありません。

80
Robert Estivill

パラメータでヘッダーを渡すと役立ちます。次のコードをご覧ください。

 @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());
11
Irfan Ul Haq

レトロフィット2の動的ヘッダー

Retrofit 2にDynamic Headerを追加するのに苦労しました。

私は非常に多くのブログとStackOverフローを経験しました。誰もがインターセプターで例を示しています。

そして、それは賢明なことではありません。1回のAPI呼び出しだけで、多くの作業を行う必要があります。

Funの引数として@ HeaderMapを追加するだけです。私は非常に簡単な方法でやった:-

In Kotlin

    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>

ここの2番目の引数にはJsonObjectがあります。渡す必要があるものは何でも置き換えることができますし、削除することもできます。

Javaの場合

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

ここの2番目の引数にはJsonObjectがあります。渡す必要があるものは何でも置き換えることができますし、削除することもできます。

0
user2610335