web-dev-qa-db-de.com

Dynamisches Setzen von Headern in Retrofit (Android)

Ich verwende eine API, die ein Autorisierungsschema verwendet, für das ein spezieller "X-Authorization" -Header festgelegt werden muss, um die Anforderung zu authentifizieren. Dieses Retrofit-Setup funktioniert beispielsweise perfekt für den Benutzer, dessen Authentifizierungstoken abc123 Lautet:

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

Ich habe Zugriff auf das X-Authorization-Token des Benutzers, kann es jedoch nicht einfach in der @ Headers-Deklaration ablegen.

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

Ich erhalte hier einen Kompilierungsfehler: Error:(41, 34) error: element value must be a constant expression

Irgendwelche Ideen, wie ich das umgehen könnte?

49
johncorser

Seit Retrofit 2.0 haben Sie zwei Möglichkeiten


1) Verwenden Sie mit OkHttp 2.2+ Interceptor

Auf der HTTP-Ebene haben Sie mehr Kontrolle über die Anforderung, sodass Sie beispielsweise Header nur auf eine bestimmte Anforderung anwenden können, die an einen bestimmten Endpunkt gesendet wurde, und so weiter.

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 Kommentar als weitere Option hinzufügen, da dies ebenfalls gültig ist.

2) Setzen Sie @ Header auf einen Methodenparameter und übergeben Sie ihn beim Aufrufen als Wert.

Aus dem docs :

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

Header-Parameter können null sein, wodurch sie in der Anforderung nicht berücksichtigt werden. Das Übergeben einer Liste oder eines Arrays führt zu einer Kopfzeile für jedes Nicht-Null-Element.

Hinweis: Überschriften überschreiben sich nicht. Alle gleichnamigen Header werden in die Anfrage aufgenommen.


EDIT: Diese Option sollte nicht als Retrofit 2 angesehen werden. * Die Unterstützung für Abfangjäger wurde eingestellt.

3) Nachrüsten des RequestInterceptor durch den Benutzer

Aus den Dokumenten: Fangen Sie jede Anforderung ab, bevor sie ausgeführt wird, um zusätzliche Daten hinzuzufügen.

Sie könnten so etwas tun

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

Das "Problem" bei diesem Ansatz ist, dass der Interceptor auf allen Endpunkten ausgeführt wird, da er auf der RestAdapter-Ebene festgelegt ist und nicht pro Endpunkt. Außerdem macht das RequestFacade nicht viele Informationen über die Anforderung verfügbar, sodass es keine Chance gibt, viel Logik darum herum hinzuzufügen.

80
Robert Estivill

Es wäre hilfreich, den Header im Parameter zu übergeben. Schauen Sie sich den folgenden Code an.

 @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

Dynamic Header In Retrofit 2

Ich habe zu viel Mühe gehabt, um Dynamic Header in Retrofit 2 hinzuzufügen.

Ich habe so viele Blogs und StackOver-Flows durchlaufen. Jeder hat ein Beispiel mit Interceptor gezeigt.

Und es ist keine kluge Sache, nur für einen API-Aufruf müssen wir so viel Arbeit leisten.

Sie müssen nur @ HeaderMap als Argument für Spaß hinzufügen. Ich habe auf sehr einfache Weise getan: -

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. Argument hier habe ich JsonObject. Sie können durch alles ersetzen, was Sie übergeben müssen, oder Sie können es auch entfernen.

In 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. Argument hier habe ich JsonObject. Sie können durch alles ersetzen, was Sie übergeben müssen, oder Sie können es auch entfernen.

0
user2610335