为了紧跟潮流,之前在公司新开项目中设计使用了MVP+Retrofit+Dagger2模式的开发框架,但由于当时时间紧,任务重。尝试去通过拦截器添加基础参数,但是POST请求一直不成功,最终无奈放弃,使用了最Low的方式,GET,POST请求全部是用@QueryMap注解来添加请求参数,然后将基础参数封装一个公共的方法,每次请求接口时调用。这也成为了我心中一直的一个梗,久久不能释怀。后来曾多次尝试解决,一直不得其法,今天终于解决了!!!并在发现了是一个极其低级的错误,反思还是自己对Retrofit没有去了解,连基本用法也用的马马虎虎。特此记录!
废了这么多话,现在开始重点!
App在与后台交互时,通常会存在一些基础公共的请求参数,比如 "用户Id",“版本号”,“平台号”等等;这些参数是任何接口请求都会添加的请求参数。这种重复代码工作,我们首先想到的肯定就是使用拦截器。而Retrofit这种优秀的网络请求框架就支持众多功能强大拦截器,主要包括请求前操作拦截器(对Request 参数进行处理)和请求后操作拦截器(对Response数据进行处理)。
今天主要介绍一下请求前操作拦截器-添加基础公共参数拦截器实现
/**
* Retrofit 基本参数拦截器
*/
public class CommonParamInterceptor implements Interceptor {
/**
* 请求方法-GET
*/
private static final String REQUEST_METHOD_GET = "GET";
/**
* 请求方法POST
*/
private static final String REQUEST_METHOD_POST = "POST";
/**
* 基础参数-平台号
*/
private static final String REQUEST_COMMON_PARAM_PLATFORM = "2";
/**
* 基础参数-个体户Id
*/
private static final String REQUEST_COMMON_PARAM_PERSONALID = "0";
/**
* 基础参数-未登录 userId
*/
private static final String REQUEST_COMMON_PARAM_USERID_DEFAULT = "0";
/**
* 基础参数-未登录 token
*/
private static final String REQUEST_COMMON_PARAM_TOKEN_DEFAULT = "";
@Override
public Response intercept(Chain chain) throws IOException {
//获取原先的请求对象
Request request = chain.request();
if (REQUEST_METHOD_GET.equals(request.method())) {
request = addGetBaseParams(request);
} else if (REQUEST_METHOD_POST.equals(request.method())) {
request = addPostBaseParams(request);
}
return chain.proceed(request);
}
/**
* 添加GET方法基础参数
*
* @param request
* @return
*/
private Request addGetBaseParams(Request request) {
HttpUrl httpUrl = request.url()
.newBuilder()
.addQueryParameter("platform", REQUEST_COMMON_PARAM_PLATFORM)//平台号
.addQueryParameter("version", ToolHelper.getVersionName())//版本号
.addQueryParameter("enterpriseId", FSaveData.Login.getEnterpriseId())//企业Id
.addQueryParameter("personalId", REQUEST_COMMON_PARAM_PERSONALID)//个体户id
.build();
//根据登录状态添加userId&&token
if (ToolHelper.logined()) {
httpUrl = httpUrl.newBuilder()
.addQueryParameter("userId", FSaveData.Login.getUserId())
.addQueryParameter("token", FSaveData.Login.getToken())
.build();
} else {
httpUrl = httpUrl.newBuilder()
.addQueryParameter("userId", REQUEST_COMMON_PARAM_USERID_DEFAULT)
.addQueryParameter("token", REQUEST_COMMON_PARAM_TOKEN_DEFAULT)
.build();
}
//添加签名
Set nameSet = httpUrl.queryParameterNames();
ArrayList nameList = new ArrayList<>();
nameList.addAll(nameSet);
Map paramMap = new HashMap<>();
for (int i = 0; i < nameList.size(); i++) {
paramMap.put(nameList.get(i), httpUrl.queryParameterValue(i));
}
httpUrl = httpUrl.newBuilder().addQueryParameter("sign", ToolHelper.dataSignature(paramMap)).build();
request = request.newBuilder().url(httpUrl).build();
return request;
}
/**
* 添加POST方法基础参数
*
* @param request
* @return
*/
private Request addPostBaseParams(Request request) {
/**
* request.body() instanceof FormBody 为true的条件为:
* 在ApiService 中将POST请求中设置
* 1,请求参数注解为@FieldMap
* 2,方法注解为@FormUrlEncoded
*/
if (request.body() instanceof FormBody) {
FormBody formBody = (FormBody) request.body();
FormBody.Builder builder = new FormBody.Builder();
for (int i = 0; i < formBody.size(); i++) {
//@FieldMap 注解 Map元素中 key 与 value 皆不能为null,否则会出现NullPointerException
if (formBody.value(i) != null)
builder.add(formBody.name(i), formBody.value(i));
}
builder
.add("platform", REQUEST_COMMON_PARAM_PLATFORM)//平台
.add("version", ToolHelper.getVersionName())//版本号
.add("enterpriseId", FSaveData.Login.getEnterpriseId())//企业Id
.add("personalId", REQUEST_COMMON_PARAM_PERSONALID);//个体户id
//根据登录状态添加userId&&token
if (ToolHelper.logined()) {
builder
.add("userId", FSaveData.Login.getUserId())
.add("token", FSaveData.Login.getToken());
} else {
builder
.add("userId", REQUEST_COMMON_PARAM_USERID_DEFAULT)
.add("token", REQUEST_COMMON_PARAM_TOKEN_DEFAULT);
}
//添加签名
Map paramMap = new HashMap<>();
formBody = builder.build();
for (int i = 0; i < formBody.size(); i++) {
paramMap.put(formBody.name(i), formBody.value(i));
}
formBody = builder
.add("sign", ToolHelper.dataSignature(paramMap))
.build();
request = request.newBuilder().post(formBody).build();
}
return request;
}
}
如代码注释所言,我所犯下的低级错误就是,无论GET,还是POST请求,全部都是用了@QueryMap参数注解,而@Query,@QueryMap仅仅是Retrofit中对@GET注解提供的请求参数注解。@POST注解合适的是@Field 和 @FieldMap注解,否则POST方式下
request.body() instanceof FormBody
永远都为fasle!!!
正确使用@GET,@POST:
@GET("mobileVerify")
Observable checkPhone(@QueryMap Map stringObject);
@POST("register")
@FormUrlEncoded
Observable register(@FieldMap Map map);
Retrofit2 注解相关请参考:Retrofit2 ,Dagger2等常用框架注解功能介绍
最后为Retrofit添加拦截器
/**
* 获取全局Retrofit实例对象
* 用于非集成公共基类BaseActivity && BaseFragment情况下进行网络请求使用
* 采用Double Check Lock 单例模式
* 添加超时时间&&基础公共参数拦截器&&网络请求返回信息打印拦截器
*/
public class RetrofitHelpter {
private static final int TOME_OUT = 100; //超时时间
private static Retrofit mInstance = null;
private RetrofitHelpter() {
}
/**
* 提供Retrofit实例对象
* DCL单例模式
*
* @return
*/
public static Retrofit getInstance() {
if (mInstance == null) {
synchronized (Retrofit.class) {
if (mInstance == null) {
mInstance = new Retrofit.Builder()
.baseUrl(API.BASE_URL)
.client(providerOkHttpClient())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())//使用rxjava
.addConverterFactory(GsonConverterFactory.create())//使用Gson
.build();
}
}
}
return mInstance;
}
/**
* 提供OkhttpClient实例对象
*
* @return
*/
private static OkHttpClient providerOkHttpClient() {
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.connectTimeout(TOME_OUT, TimeUnit.SECONDS)
.readTimeout(TOME_OUT, TimeUnit.SECONDS)
.addNetworkInterceptor(providerNetworkInterceptor())
.addInterceptor(providerInterceptor());
return builder.build();
}
/**
* 提供网络请求返回信息打印拦截器
*
* @return
*/
private static Interceptor providerNetworkInterceptor() {
return new RequestIntercept(null);
}
/**
* 基础公共参数拦截器
*
* @return
*/
private static Interceptor providerInterceptor() {
return new CommonParamInterceptor();
}
}