1. ホーム
  2. android

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

2023-12-04 23:02:05

質問

私は、リクエストを認証するために特別な "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

これを回避する方法について何かアイデアはありますか?

どのように解決するのですか?

Retrofit 2.0以降では、次の2つの方法があります。


1) OkHttp 2.2+ を使用する場合 インターセプター

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


編集 : 追加 ジェイク・ウォーソン のコメントを追加するのも有効です。

2) 置く ヘッダ をメソッドのパラメータにつけて、起動時に値として渡します。

から ドキュメント :

// 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 はリクエストに関する情報をあまり公開しないので、 それに関するロジックをあまり追加する機会がありません。