对开发中遇到的问题进行整理记录~~
场景:Token验证较多的Android应用;
需求:在Token过期后,向服务器重新获取Token并使用新Token重新发起请求;
实现: 参考:http://www.jianshu.com/p/62ab11ddacc8
1、服务器若能在Token过期时返回401错误码,则可以使用OkHttp提供的Authenticator接口(未验证);
2、实现OkHttp的Interceptor接口,并使用同步的Retrofit请求
public class TokenInterceptor implements Interceptor { @ParametersAreNonnullByDefault @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); Response originalResponse = chain.proceed(request); String url = request.url().toString();//请求Url //获取返回的json,response.body().string();只有效一次,对返回数据进行转换 ResponseBody responseBody = originalResponse.body(); BufferedSource source = responseBody.source(); source.request(Long.MAX_VALUE); // Buffer the entire body. Buffer buffer = source.buffer(); Charset charset = Charset.forName("UTF-8"); MediaType contentType = responseBody.contentType(); if (contentType != null) { charset = contentType.charset(Charset.forName("UTF-8")); } String bodyString = buffer.clone().readString(charset);//首次请求返回的结果 if (isTokenExpired(bodyString)) {//根据和服务端的约定判断token过期 //同步请求方式,获取最新的Token TokenEntity tokenEntity = getNewToken(); //使用新的Token,创建新的请求 if(request.body() instanceof FormBody){ FormBody.Builder newFormBody = new FormBody.Builder(); FormBody oidFormBody = (FormBody) request.body(); for (int i = 0;i<oidFormBody.size();i++){ //根据需求修改参数 if ("需要更新的token参数字段".equals(oidFormBody.encodedName(i))) { newFormBody.addEncoded(oidFormBody.encodedName(i),tokenEntity.getToken()); }else { newFormBody.addEncoded(oidFormBody.encodedName(i),oidFormBody.encodedValue(i)); } } Request.Builder builder = request.newBuilder(); builder.url(url); builder.method(request.method(),newFormBody.build()); request = builder.build(); } originalResponse.body().close(); //重新请求 return chain.proceed(request); } return originalResponse; } /** * 根据Response约定,判断Token是否失效 * @param response */ private boolean isTokenExpired(String response) { JSONObject obj = null; try { obj = new JSONObject(response); if ("Token过期的判断条件") { return true; } } catch (JSONException e) { e.printStackTrace(); } return false; } /** * 同步请求方式,获取最新的Token */ private LoginEntity getNewToken() throws IOException { // 通过一个特定的接口获取新的token,此处要用到同步的retrofit请求 Call<LoginEntity> loginCall = RetrofitHelper.getInstance().getRetrofit(Api.class) .getToken("参数"); return loginCall.execute().body(); }然后在OkHttp中配置
okHttpClient = new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS)//连接超时 .readTimeout(15, TimeUnit.SECONDS)//读取超时 .writeTimeout(15, TimeUnit.SECONDS)//写入超时 .addInterceptor(new TokenInterceptor())//okhttp拦截器 Application拦截 .build();