web-dev-qa-db-fra.com

Comment définir dynamiquement des en-têtes dans Retrofit (Android)

J'utilise une API qui utilise un système d'autorisation nécessitant la définition d'un en-tête "X-Authorization" spécial pour authentifier la demande. Par exemple, cette configuration Retrofit fonctionne parfaitement pour l'utilisateur dont le jeton d'autorisation est abc123:

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

Je cache le jeton X-Authorization de l'utilisateur. J'ai donc accès à cela. Cependant, je ne peux pas simplement le laisser tomber dans la déclaration @Headers.

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

Je reçois une erreur de compilation ici: Error:(41, 34) error: element value must be a constant expression

Des idées sur la façon dont je pourrais contourner cela?

49
johncorser

Depuis Retrofit 2.0, vous avez deux options.


1) En utilisant OkHttp 2.2+, utilisez Interceptor

Au niveau Http, vous avez davantage de contrôle sur la demande. Vous pouvez ainsi appliquer des en-têtes uniquement à une demande spécifique adressée à un point de terminaison spécifique, etc.

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: Ajouter @ JakeWarthon comment est une autre option, car elle est également valide.

2) Placez @ Header sur un paramètre de méthode et transmettez-le en tant que valeur lors de l'appel.

De la docs :

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

Les paramètres d'en-tête peuvent être null, ce qui les exclura de la demande. Passer une liste ou un tableau donnera un en-tête pour chaque élément non nul.

Remarque: les en-têtes ne se écrasent pas. Tous les en-têtes portant le même nom seront inclus dans la demande.


EDIT: Cette option ne doit pas être considérée comme Retrofit 2. * Suppression de la prise en charge des intercepteurs.

3) Requestoftercept post-utilisateur

A partir de la documentation: Intercepter chaque requête avant son exécution afin d'ajouter des données supplémentaires.

Vous pourriez faire quelque chose comme

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

Le "problème" avec cette approche est que l'intercepteur sera exécuté sur tous les noeuds finaux, tel qu'il est défini au niveau de RestAdapter, et non pas par noeud final. En outre, le RequestFacade n'expose pas beaucoup d'informations sur la requête, donc aucune chance d'ajouter beaucoup de logique autour de celle-ci.

80
Robert Estivill

Passer l'en-tête en paramètre serait utile. Regardez le code suivant;

 @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

en-tête dynamique en rattrapage 2

J'ai trop eu du mal à ajouter Dynamic Header In Retrofit 2.

J'ai parcouru tellement de blogs et de flux StackOver. Tout le monde a montré l'exemple avec Interceptor.

Et ce n’est pas une bonne chose. Seulement pour un appel d’API, nous devons faire autant de travail.

Vous devez simplement ajouter @ HeaderMap comme argument amusant. J'ai fait de manière très simple: -

en 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ème argument ici j'ai JsonObject. Vous pouvez remplacer par tout ce que vous avez besoin de passer ou vous pouvez également l'enlever.

en 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ème argument ici j'ai JsonObject. Vous pouvez remplacer par tout ce que vous avez besoin de passer ou vous pouvez également l'enlever.

0
user2610335