改造:如何在 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 编码。
我最近开始在我的 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 编码。