项目中联网框架使用的是Retrofit2,因为项目的接口设计了许多公共参数,需要对Retrofit网络请求参数进行进一步的封装。本文记录了参数封装的过程。
说在前面的话:由于每个公司的接口设计规则不同,这里的封装代码也会千差万别。
文章中项目的接口规则为:统一采用POST表单的方式提交到服务器,服务器返回JSON格式的数据。并且设置了公共参数,每次请求需要携带公共参数,并且添加公共的头部。
Step1
刚开始看到表单方式,觉得很激动,Retrofit2 支持 @FormUrlEncoded注解的方式来进行表单访问
所以就有了这样的Retrofit 接口设计
public interface ApiService {
@FormUrlEncoded
@POST("login")
Observable<BaseResult<String>> login(@Field("data") String json);
}
因为只有@Body注解的参数才能 被Converter 转换,所以这里方法的参数使用的String类型
接下来就是公共参数的设置,采用 拦截器的方式来完成
public class HttpParamInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request.Builder requestBuilder = request.newBuilder();
//添加公共的头部
requestBuilder.addHeader("User-Agent", "pinxiango");
String method = request.method();
//接口规则规定了请求方式为 Form 表单,这里只对Post进行处理
if ("POST".equals(method)) { //POST 请求
RequestBody body = request.body();
//因为我们项目需要获取参数 进行进一步处理,需要将参数记录下来
String data_json = ""; //传入的Json 字符串
FormBody.Builder builder = new FormBody.Builder();
FormBody formBody = (FormBody) body;
int size = formBody.size();
if (size == 0) {
builder.add("data", data_json);
} else {
//循环将传入的 表单添加到新的表单
for (int i = 0; i < size; i++) {
String name = formBody.name(i);
String value = formBody.value(i);
if ("data".equals(name)) {
data_json = value;
}
builder.add(name, value);
}
}
}
String sign = Contacts.KEY + "-" +
Contacts.version + "-" +
Contacts.app_source + "-" +
data_json;
//拼接 公共的参数
builder.add("datetime", dateTime + "");
builder.add("sign", sign);
FormBody formBody = builder.build();
//重新构建 request
request = requestBuilder
.post(formBody)
.build();
}
return chain.proceed(request);
}
}
嗯?开始愉快的使用了,用了一圈发现怎么感觉那里不对
Retrofit 对于@FormUrlEncoded注解的Post请求不支持空参数的请求
每次请求需要手动转成 Json 字符串(尤其是这一步操作,深恶痛绝)
为了解决这个问题,对ApiService 和HttpParamInterceptor进行修改
public interface ApiService {
@POST("login")
Observable<BaseResult<String>> login(@Body User user);
@POST("logout")
Observable<BaseResult<String>> logout();
}
接口设计注解全部采用 @POST的形式,需要Json 数据可以直接采用@Body 的形式 ,Converter会将其转换为Json 字符串
修改后HttpParamInterceptor 代码如下
public class HttpParamInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request.Builder requestBuilder = request.newBuilder();
//添加公共的头部
requestBuilder.addHeader("User-Agent", "pinxiango");
String method = request.method();
if ("POST".equals(method)) { //POST 请求
RequestBody body = request.body();
String data_json = ""; //传入的Json 字符串
//后台规定数据格式为 Form 表单形式
FormBody.Builder builder = new FormBody.Builder();
//由于采用的是 普通的@Post 形式
//并且经过Converter 的转换,内容为Json字符串
//这里直接进行读取
Buffer buffer = new Buffer();
body.writeTo(buffer);
data_json = buffer.readUtf8();
builder.add("data", data_json);
//系统当前的时间戳
int dateTime = (int) (new Date().getTime() / 1000);
String mde_sign = Contacts.KEY + "-" +
data_json + "-" +
dateTime;
builder.add("datetime", dateTime + "");
builder.add("sign", mde_sign);
//构建Form 表单
FormBody formBody = builder.build();
//重构请求
request = requestBuilder
.post(formBody)
.build();
}
return chain.proceed(request);
}
}
至此,参数的封装结束。可以参考以上代码 进行分页请求的分装