关于Retrofit2+Okhttp3实现统一添加请求参数和重定向
Android开发中难免会遇到一些比较“不友好”的服务端接口。比如以前遇到的json数据中,某个字段偶尔为Object,偶尔为List…
最近遇到的一个问题就是:所有请求接口都要增加一个token参数… 并且token参数有可能过期,比如请求某一条接口,如果token失效则在该请求的响应中把新的token带回来,客户端就得用新的token再次发送该请求,类似重定向。
token失效的stateCode为3,新的token在data字段中返回。如下:
1 2 3 4 5
| { "stateCode":3, "data":"E78kH6", "errorMsg":null }
|
庆幸的是,Okhttp提供了强大的拦截器功能,是一种能够监控,重写,重试调用的强大机制。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| 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。
1 2 3 4 5 6 7
| Request request = oldRequest.newBuilder() .header("Content-Encoding", "gzip") .build();
Response response = response.newBuilder() .header("Content-Encoding", "gzip") .build();
|
然后为OkHttp配置一个拦截器。
1 2 3 4 5 6 7 8 9 10
| 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
1 2 3 4 5 6 7 8
| Retrofit retrofit = new Retrofit.Builder() .addConverterFactory(ScalarsConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .baseUrl(baseUrl) .client(getOkHttpClient()) .build();
Api api = retrofit.create(Api.class);
|