關於Retrofit2+Okhttp3實現統一新增請求引數和重定向
阿新 • • 發佈:2018-10-31
Android開發中難免會遇到一些比較“不友好”的服務端介面。比如以前遇到的json資料中,某個欄位偶爾為Object,偶爾為List…
最近遇到的一個問題就是:所有請求介面都要增加一個token引數… 並且token引數有可能過期,比如請求某一條介面,如果token失效則在該請求的響應中把新的token帶回來,客戶端就得用新的token再次傳送該請求,類似重定向。
token失效的stateCode為3,新的token在data欄位中返回。如下:
{
"stateCode":3,
"data":"E78kH6",
"errorMsg":null
}
慶幸的是,Okhttp提供了強大的攔截器功能,是一種能夠監控,重寫,重試呼叫的強大機制。
public class TokenInterceptord implements Interceptor {
private final String TAG = "respond";
@Override
public Response intercept(Chain chain) throws IOException {
Request oldRequest = chain.request();
String url = oldRequest.url().toString();
Response response = null ;
// 新的請求,新增引數
Request newRequest = addParam(oldRequest);
response = chain.proceed(newRequest);
ResponseBody value = response.body();
byte[] resp = value.bytes();
String json = new String(resp, "UTF-8");
// 判斷stateCode值
try {
JSONObject jsonObject = new JSONObject(json);
int stateCode = jsonObject.optInt("stateCode");
if (stateCode == 3) {
String data = jsonObject.optString("data");
Log.d(TAG, "token失效,新的token:" + data);
DataStorageUtils.saveToken(data);
// token失效,重新執行請求
Request newTokenRequest = addParam(oldRequest);
response = chain.proceed(newTokenRequest);
} else {
// 這裡值得注意。由於前面value.bytes()把響應流讀完並關閉了,所以這裡需要重新生成一個response,否則資料就無法正常解析了
response = response.newBuilder()
.body(ResponseBody.create(null, resp))
.build();
}
} catch (Exception e) {
}
return response;
}
/**
* 新增公共引數
*
* @param oldRequest
* @return
*/
private Request addParam(Request oldRequest) {
HttpUrl.Builder builder = oldRequest.url()
.newBuilder()
.setEncodedQueryParameter("lversion", PackagesUtils.getAppVersionName())
.setEncodedQueryParameter("token", DataStorageUtils.getToken());
Request newRequest = oldRequest.newBuilder()
.method(oldRequest.method(), oldRequest.body())
.url(builder.build())
.build();
return newRequest;
}
}
當然,也可以為請求或響應新增Header。
Request request = oldRequest.newBuilder()
.header("Content-Encoding", "gzip")
.build();
Response response = response.newBuilder()
.header("Content-Encoding", "gzip")
.build();
然後為OkHttp配置一個攔截器。
public static OkHttpClient getOkHttpClient() {
Interceptor interceptor = new TokenInterceptor();
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(30 * 1000, TimeUnit.MILLISECONDS)
.readTimeout(30 * 1000, TimeUnit.MILLISECONDS)
.addInterceptor(interceptor)
.addInterceptor(new HttpLoggingInterceptor(new MyLog()).setLevel(HttpLoggingInterceptor.Level.BODY))
.build();
return client;
}
Retrofit 使用 Okhttp作為client
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(baseUrl)
.client(getOkHttpClient())
.build();
Api api = retrofit.create(Api.class);