一、需求和问题
在开发Android项目时,一定需要和后端对接网络请求,但在因为现在都JSON格式的数据结构,在数据字段前后不一致是Android端是无法判断是是字段错误还是数据本身没有值。所有在数据还没有被Gson反序列前拦截 回应并打印body 就可以知道后端传过来的知道和值的真实情况。
这样就很清楚是Android端的问题还是后端的问题,也可以减少debug的时间。
二、依赖和配置
//retrofit2
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
//Gson
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
//Jackson
//implementation 'com.squareup.retrofit2:converter-jackson:2.9.0'
implementation 'com.squareup.retrofit2:converter-scalars:2.9.0'
//RxJava3的适配器
implementation 'com.squareup.retrofit2:adapter-rxjava3:2.9.0'
//OkHttp3
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
//Rxjava3 + RxAndroid3
implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
implementation 'io.reactivex.rxjava3:rxjava:3.0.0'
// Logger 日志插件
implementation 'com.orhanobut:logger:2.2.0'
关于Okhttp3+retrofit2+Rxjava3的具体配置可以参考自学Android开发 我的Retrofit2+RxJava3的封装
三、代码示例
拦截器代码:
public class OkHttpInterceptor implements Interceptor {
private final Charset UTF8 = Charset.forName("UTF-8");
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
RequestBody requestBody = request.body();
String bodyStr = "";
if (requestBody != null) {
Buffer buffer = new Buffer();
requestBody.writeTo(buffer);
Charset charset = UTF8;
MediaType contentType = requestBody.contentType();
if (contentType != null) {
charset = contentType.charset(UTF8);
}
bodyStr = buffer.readString(charset);
}
String header = GsonUtil.Companion.getGson().toJson(request.headers());
bodyStr = bodyStr == "" ? "无参数" : bodyStr;
Response response = chain.proceed(request);
ResponseBody responseBody = response.body();
String bodyStrRespon = "";
BufferedSource source = responseBody.source();
source.request(Long.MAX_VALUE);
Buffer buffer = source.getBuffer();
Charset charset = UTF8;
MediaType contentType = responseBody.contentType();
if (contentType != null) {
try {
charset = contentType.charset(UTF8);
} catch (UnsupportedCharsetException e) {
e.printStackTrace();
}
}
bodyStrRespon = buffer.clone().readString(charset);
bodyStrRespon = bodyStrRespon == "" ? "无响应Body" : bodyStrRespon;
String url = GsonUtil.Companion.getGson().toJson(response.request().url());
String msg = "{\"Response\":{\"code\":" + response.code()
+ ",\"method\":\" " + request.method()+"\""
+ ",\"请求url\":" + url
+ ",\"请求头\":" + header
+ ",\"请求参数\":" + bodyStr
+ ",\"响应body\":" + bodyStrRespon
+ "}}";
if (response.code() == 200)
LogUtil.Companion.gsonToInfo(msg);
else
LogUtil.Companion.error(msg);
return response;
}
}
LogUtil.Companion.gsonToInfo使用的是Kotlin 封装的logger 工具类,这里虽然使用的是Logger日志工具包,这个log工具包 有好处也有坏处,具体打印工具选择熟悉的。
Interceptor在这里虽然只做了拦截打印请求参数和回应数据,但是如果有前后端需要对数据进行加密时,就只需要更改这里就能完成请求加密和响应结果的解密的处理。
在一些需要对请求头有特殊要求的也可以在这里使用request().newBuilder() 新建一个request又携带旧request的数据,但你可以在这个新的request对旧的数据进行修改覆盖等,如添加请求头等操作。
注意:在打印请求和回复参数时,要注意文件上传时,不要使用这个拦截器,不然会打印文件编码符的,所以建议编写两个拦截器,上传文件时使用不打印请求体 只打印回复体参数。