Retrofit2:在OkHttp Interceptor中修改请求体

时间:2016-01-14 13:46:11

标签: android retrofit okhttp

我在Android应用程序中使用Retrofit 2(2.0.0-beta3)和OkHttp客户端,到目前为止一切都很顺利。但目前我正面临着OkHttp Interceptor的问题。我正在与之通信的服务器正在请求主体中访问令牌,因此当我需要添加更新的身份验证令牌时,当我拦截添加身份验证令牌的身份验证或身份验证器的身份验证方法时,我需要为此目的修改请求体。但看起来我只能在标题中添加数据,但不能在正在进行的请求中添加数据。我到目前为止编写的代码如下:

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

有人能指出正确的方向,如何修改请求体以添加我的访问令牌(第一次或在令牌刷新后更新)?任何指向正确方向的指针都将受到赞赏。

5 个答案:

答案 0 :(得分:27)

我用它来将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", "Jurassic@Park.com")
            .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", "Jurassic@Park.com")
                .add("tel", "90301171XX")
                .build();

答案 1 :(得分:4)

由于这不能写在@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);
    }

}

答案 2 :(得分:1)

我将使用Dagger分享我对@Fabian答案的Kotlin实现。我想将origin=app添加到GET请求的请求网址中,并添加到表单编码的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()
}

答案 3 :(得分:0)

我正在使用这种方式来验证我的令牌

final OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(30, TimeUnit.SECONDS) //retrofit default 10 seconds
                .writeTimeout(30, TimeUnit.SECONDS) //retrofit default 10 seconds
                .readTimeout(30, TimeUnit.SECONDS) //retrofit default 10 seconds
                .addInterceptor(logging.setLevel(HttpLoggingInterceptor.Level.BODY))
                .addInterceptor(new BasicAuthInterceptor())
                .build();

这里我通过BasicAuthInterceptor发送令牌

public class MyServiceInterceptor implements Interceptor {

private String HEADER_NAME="Authorization";
private String OBJECT_NAME="Bearer";
private String SPACE="  ";
@Override public Response intercept(Chain chain) throws IOException {
    Request request = chain.request();

    Request.Builder requestBuilder = request.newBuilder();

    String token= PreferenceManager.getInstance().getString(PreferenceManager.TOKEN);
        if (token != null) { {
            requestBuilder.addHeader(HEADER_NAME, OBJECT_NAME+SPACE+ token);
        }
}

    return chain.proceed(requestBuilder.build());

} }

答案 4 :(得分:0)

private static class NetworkInterceptor implements Interceptor {

@Override
public Response intercept(Chain chain) throws IOException {
    
    Request request = chain.request();
    RequestBody oldBody = request.body(); //retrieve the current request body
    Buffer buffer = new Buffer();
    oldBody.writeTo(buffer);
    String strOldBody = buffer.readUtf8(); // String representation of the current request body
    buffer.clear();
    buffer.close();

    MediaType mediaType = MediaType.parse("application/json; charset=UTF-8");
    String strNewBody = enDecService.encryptBody(strOldBody); // Your encryption/ modification logic 
    RequestBody body = RequestBody.create(mediaType, strNewBody); // New request body with the encrypted/modified string of the current request body

    request = request.newBuilder()
            .header("Content-Type", "application/json")
            .header("Content-Length", String.valueOf(body.contentLength()))
            .header("Authorization", "Bearer " + "your token")
            .method(request.method(), body).build();


    long t1 = System.nanoTime();
    Log.d(TAG, String.format("Sending request %s on %s", request.url(), request.headers()));

    Response response = chain.proceed(request); // sending req. to server. current req. body is a encrypted string.
    int maxAge = 6000; // read from cache for 6000 seconds even if there is internet connection
    response.header("Cache-Control", "public, max-age=" + maxAge);
    response = response.newBuilder().removeHeader("Pragma").build();


    long t2 = System.nanoTime();
    Log.d(TAG, String.format("Received response for %s in %.1fms  %s", response.request().url(), (t2 - t1) / 1e6d, response.toString()));

    try {
        String s = response.body().string(); // retrieve string representation of encrypted response assuming your response is encrypted.
        ResponseBody responseBody = ResponseBody.create(mediaType, enDecService.decryptBody(s)); // decrypt the encrypted response or make other modifications.yor decryption/modifications logic goes here.
        response = response.newBuilder().body(responseBody).build(); // build a new response with the decrypted response body.
    } catch (JOSEException e) {

    } catch (ParseException e) {

    }
    return response;
}

}