改造:如何在 POST 中发送 base64 编码的正文请求

Retrofit : how to send base64 encoded body request in POST

我最近开始在我的 android 应用程序中使用 Retrofit,这是我添加用户的改造请求:

RestAdapter mRestAdapter =  new RestAdapter.Builder()
        .setEndpoint(SERVER_URL)
        .setLogLevel(RestAdapter.LogLevel.FULL)
        .setRequestInterceptor(new SessionInterceptor())
        .setClient(new OkClient(new OkHttpClient()))
        .build();

@POST("/user/add")
    JsonElement registerUser(@Body User user);

这里的 User 是我要在服务器上注册的用户的模型 class。问题是服务器期望 json 正文请求采用 Base64.encode() 格式。有没有办法使用 retrofit 发送 Base64 编码的数据?

我可以想到像这样手动操作:

String json = gson.toJson(user);
byte[] bytes = Base64.encode(json.getBytes("UTF-8"), Base64.DEFAULT);

然后在请求中传递它。但是,我必须手动完成每个 POST 请求。有没有更简洁的方法来做到这一点。

对于一般对象类型(包括字符串),Retrofit 将使用它的 Converter 来序列化值。在这种情况下,默认使用 Gson 将正文序列化为 JSON.

要上传 Base64 编码的数据,您需要使用 TypedInput。这告诉 Retrofit 您将向它传递已经序列化的原始主体和关联的 Content-Type 值。

这个答案直接适用于 Retrofit v2.0,但同样的概念可以适用于更早的版本。

一个选择是创建一个 RequestInterceptor。根据您提供的信息,我不太确定 every POST 是否要进行 base 64 编码。我假设是这种情况。

public class Base64EncodeRequestInterceptor implements Interceptor {

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request originalRequest = chain.request();
        Request.Builder builder = originalRequest.newBuilder();

        if (originalRequest.method().equalsIgnoreCase(POST)) {
          builder = originalRequest.newBuilder()
              .method(originalRequest.method(), encode(originalRequest.body()));
        }


        return chain.proceed(builder.build());
    }

    private RequestBody encode(RequestBody body) {
        return new RequestBody() {
            @Override
            public MediaType contentType() {
                return body.contentType();
            }

            @Override
            public void writeTo(BufferedSink sink) throws IOException {
                Buffer buffer = new Buffer();
                body.writeTo(buffer);
                byte[] encoded = Base64.encode(buffer.readByteArray(), Base64.DEFAULT);
                sink.write(encoded);
                buffer.close();
                sink.close();
            }
        };
    }
}

这个拦截器所做的是检查传入的方法是否是 POST,如果是,它将对 RequestBody 进行 base64 编码。