學習rxjava和retrofit搭建demo時,用到了公司接口,由於公司的所有網絡請求數據都有進行加密,這給搭建demo的過程中增加了一些困難,這裏將學習以及一些走彎路的過程記錄下來。
1、rxjava+retrofit加解密方案
這裏先簡單介紹一下rxjava+retrofit使用方法
1.1構造服務ApiService
1.2通過retrofit生成ApiService實例
1.3封裝業務方法提供給前臺使用
其中98-112行爲參數的封裝,不同公司有不同的規則,不必過多糾結;
107行爲數據加密,根據自家公司加密方法進行加密;
可以看到定義的ApiService返回爲較原始的ResponseBody,我們不能在頁面上使用api時還進行ResponseBody到所需javaBean的轉換,可能有同學會疑惑這裏爲什麼不直接返回頁面所需的javaBean,道理很簡單,因爲數據加密了,結構與目標javaBean已經完全不同,你如果直接去進行轉換是肯定拿不到你想要的javaBean的,於是想到通過rxjava自身的特點,117行用map操作符將responseBody的string取出後進行解密,然後返回對應泛型的javaBean。
整個加解密的過程比較簡單,中間還是踩了不少坑。
2、過程中遇到的坑
2.1在哪解密?
最開始想到的解密是在OkHttp Interceptor(攔截器)中進行解密。攔截器代碼如下:
public class BaseInterceptor implements Interceptor
{
private Map<String, String> headers;
public BaseInterceptor(Map<String, String> headers)
{
this.headers = headers;
}
@Override
public Response intercept(Chain chain) throws IOException
{
Request.Builder builder = chain.request().newBuilder();
if (headers != null && headers.size() > 0)
{
Set<String> keys = headers.keySet();
for (String headerKey : keys)
{
builder.addHeader(headerKey, headers.get(headerKey)).build();
}
}
Response response = chain.proceed(builder.build());
return decrypt(response);
}
/**
* 解密過程
*
* @param response
* @return
* @throws IOException
*/
private Response decrypt(Response response) throws IOException
{
String oldBody = response.body().string();
Log.i("Interceptor", "oldBody=" + oldBody);
ServerResponse resp = new Gson().fromJson(oldBody, ServerResponse.class);
String data = null == resp.getData() ? null : (String) resp.getData();
String newBody = null;
if (!TextUtils.isEmpty(data))
{
String str = DES3EncryptAndDecrypt.des3DecryptMode(data);
newBody = oldBody.replace("\"" + data + "\"", str);
}
Response res = response.newBuilder().body(ResponseBody.create(null, newBody)).build();
return res;
}
}
思路很簡單,就是在37行攔截到response後取出responseBody,然後解密後用明文重新構造一個response返給上層,但是後面發現rxjava會報出一個closed的錯誤,且控制檯沒有任何錯誤信息,在苦苦找不到結果後,QJay大神說response.body().string()會關流,於是進入string()方法看到以下代碼:明顯finally中關掉了source,導致response根本到不了上層了。
其實上面的問題無非就是body不能獲取到而已,好在HttpLoggingInterceptor裏面有如何獲取到responcebody的方法,這裏就不貼HttpLoggingInterceptor源碼了,內部比較簡單,無非就是根據一些條件打印一些信息而已,這裏只貼出獲取responseBody的代碼,如下:
獲取到responseBody後以爲不會再有什麼問題,將程序跑起來後發現,解密根本沒有成功,雖然原responseBody中的密文已拿到,且已成功解密,但是發現在這裏根本沒有方法來構造response,也就是說不能將攔截到的response中的密文替換問明文,終於這種思路有一個點是始終跨不過的,最後便放棄了這種方案,改爲以上方案解決了解密問題。