web-dev-qa-db-fra.com

Retrofit2: Modification du corps de la demande dans OkHttp Interceptor

J'utilise Retrofit 2 (2.0.0-beta3) avec le client OkHttp dans l'application Android et jusqu'à présent tout va bien. Mais actuellement, je rencontre un problème avec OkHttp Interceptor. Le serveur avec lequel je communique prend le jeton d'accès dans le corps de la demande, donc lorsque j'intercepte la demande d'ajout de jeton d'authentification ou dans la méthode d'authentification d'Authenticator lorsque j'ai besoin d'ajouter un jeton d'authentification mis à jour, je dois modifier le corps de la demande à cet effet. Mais il semble que je peut uniquement ajouter des données dans les en-têtes mais pas dans le corps de la demande en cours. Le code que j'ai écrit jusqu'à présent est le suivant:

client.interceptors().add(new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request request = chain.request();
                if (UserPreferences.ACCESS_TOKEN != null) {
                    // need to add this access token in request body as encoded form field instead of header
                    request = request.newBuilder()
                            .header("access_token", UserPreferences.ACCESS_TOKEN))
                            .method(request.method(), request.body())
                            .build();
                }
                Response response = chain.proceed(request);
                return response;
            }
        });

Quelqu'un peut-il m'orienter dans la bonne direction pour savoir comment modifier le corps de la demande pour ajouter mon jeton d'accès (première fois ou mis à jour après l'actualisation du jeton)? Tout pointeur dans la bonne direction serait apprécié.

23
Lala Rukh

J'utilise cela pour ajouter un paramètre de post à ceux existants.

 OkHttpClient client = new OkHttpClient.Builder()
                    .protocols(protocols)
                    .addInterceptor(new Interceptor() {
                        @Override
                        public Response intercept(Chain chain) throws IOException {
                            Request request = chain.request();
                            Request.Builder requestBuilder = request.newBuilder();
RequestBody formBody = new FormEncodingBuilder()
            .add("email", "[email protected]")
            .add("tel", "90301171XX")
            .build();
                            String postBodyString = Utils.bodyToString(request.body());
                            postBodyString += ((postBodyString.length() > 0) ? "&" : "") +  Utils.bodyToString(formBody);
                            request = requestBuilder
                                    .post(RequestBody.create(MediaType.parse("application/x-www-form-urlencoded;charset=UTF-8"), postBodyString))
                                    .build();
                            return chain.proceed(request);
                        }
                    })
                    .build();

public static String bodyToString(final RequestBody request){
        try {
            final RequestBody copy = request;
            final Buffer buffer = new Buffer();
            if(copy != null)
                copy.writeTo(buffer);
            else
                return "";
            return buffer.readUtf8();
        }
        catch (final IOException e) {
            return "did not work";
        }
    }

OkHttp3:

RequestBody formBody = new FormBody.Builder()
                .add("email", "[email protected]")
                .add("tel", "90301171XX")
                .build();
30
Fabian

Comme cela ne peut pas être écrit dans les commentaires de la réponse précédente de @Fabian, je poste celle-ci en tant que réponse distincte. Cette réponse concerne à la fois "application/json" ainsi que les données de formulaire.

import Android.content.Context;

import org.json.JSONException;
import org.json.JSONObject;

import Java.io.IOException;

import okhttp3.FormBody;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.Buffer;

/**
 * Created by debanjan on 16/4/17.
 */

public class TokenInterceptor implements Interceptor {
    private Context context; //This is here because I needed it for some other cause 

    //private static final String TOKEN_IDENTIFIER = "token_id";
    public TokenInterceptor(Context context) {
        this.context = context;
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        RequestBody requestBody = request.body();
        String token = "toku";//whatever or however you get it.
        String subtype = requestBody.contentType().subtype();
        if(subtype.contains("json")){
            requestBody = processApplicationJsonRequestBody(requestBody, token);
        }
        else if(subtype.contains("form")){
            requestBody = processFormDataRequestBody(requestBody, token);
        }
        if(requestBody != null) {
            Request.Builder requestBuilder = request.newBuilder();
            request = requestBuilder
                    .post(requestBody)
                    .build();
        }

        return chain.proceed(request);
    }
    private String bodyToString(final RequestBody request){
        try {
            final RequestBody copy = request;
            final Buffer buffer = new Buffer();
            if(copy != null)
                copy.writeTo(buffer);
            else
                return "";
            return buffer.readUtf8();
        }
        catch (final IOException e) {
            return "did not work";
        }
    }
    private RequestBody processApplicationJsonRequestBody(RequestBody requestBody,String token){
        String customReq = bodyToString(requestBody);
        try {
            JSONObject obj = new JSONObject(customReq);
            obj.put("token", token);
            return RequestBody.create(requestBody.contentType(), obj.toString());
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return null;
    }
    private RequestBody processFormDataRequestBody(RequestBody requestBody, String token){
        RequestBody formBody = new FormBody.Builder()
                .add("token", token)
                .build();
        String postBodyString = bodyToString(requestBody);
        postBodyString += ((postBodyString.length() > 0) ? "&" : "") +  bodyToString(formBody);
        return RequestBody.create(requestBody.contentType(), postBodyString);
    }

}
5
Debanjan

Je vais partager mon implémentation Kotlin de la réponse de @ Fabian en utilisant Dagger. Je voulais Origin=app ajouté à l'URL de demande pour les demandes GET et ajouté au corps pour les demandes codées par formulaire POST requêtes

@Provides
@Singleton
fun providesRequestInterceptor() =
        Interceptor {
            val request = it.request()

            it.proceed(when (request.method()) {
                "GET" -> {
                    val url = request.url()
                    request.newBuilder()
                            .url(url.newBuilder()
                                    .addQueryParameter("Origin", "app")
                                    .build())
                            .build()
                }
                "POST" -> {
                    val body = request.body()
                    request.newBuilder()
                            .post(RequestBody.create(body?.contentType(),
                                    body.bodyToString() + "&Origin=app"))
                            .build()
                }
                else -> request
            })
        }

fun RequestBody?.bodyToString(): String {
    if (this == null) return ""
    val buffer = okio.Buffer()
    writeTo(buffer)
    return buffer.readUtf8()
}
2
mgray88