web-dev-qa-db-ja.com

Retrofit2:OkHttpインターセプターでのリクエストボディの変更

私は、Retrofit 2(2.0.0-beta3)をOkHttpクライアントでAndroidアプリケーションとこれまでのすべてが順調に進んでいます。しかし、現在、OkHttp Interceptorの問題に直面しています。リクエストの本文でアクセストークンを取得しているので、更新された認証トークンを追加する必要があるときに認証トークンを追加するリクエストを認証するか、Authenticatorの認証メソッドでリクエストボディを変更する必要があります。ヘッダーにのみデータを追加できますが、進行中のリクエストの本文には追加できません。これまでに書いたコードは次のとおりです。

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

リクエストボディを変更してアクセストークンを追加する方法(初回またはトークンの更新後に更新する方法)として、誰かが正しい方向を示すことができますか?正しい方向への任意のポインタをいただければ幸いです。

23
Lala Rukh

これを使用して、既存のパラメーターにpostパラメーターを追加します。

 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

これは、@ Fabianによる前の回答のコメントには記述できないため、この回答を別の回答として投稿しています。この回答では、「application/json」とフォームデータの両方を扱います。

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

ダガーを使用して、@ Fabianの答えのKotlin実装を共有します。私は欲しかった Origin=app GETリクエストのリクエストURLに追加され、フォームエンコードPOSTリクエストのボディに追加されました

@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