Android OkHttp Retrofit Token过期重新请求接口

遇到问题:

请求接口时遇到token过期重新获取token之后,不会再次请求当前接口。

解决办法:

在 OkHttpManager 这个类 里面 直接把 30001 和30002 拦截 重新获取接口 在重新请求一遍方法 虽然是这么简单,但是走了好多弯路,所以几下笔记,避免更多小伙伴踩坑

参考:

http://www.jianshu.com/p/8d1ee61bc2d2

遇到的坑

报java.lang.IllegalStateException: closed,java.lang.IllegalStateException: closed,原因为OkHttp请求回调中response.body().string()只能有效调用一次

解决办法

     @Override
    public Response intercept(Chain chain) throws IOException
    {
        Request request = chain.request();
        logForRequest(request);
        Response response = chain.proceed(request);
       MediaType mediaType = response.body().contentType();
        String content= response.body().string();
        Log.e("tag", content);
        return response.newBuilder()
                .body(ResponseBody.create(mediaType, string))
                .build();
      // return logForResponse(response);

贴出代码部分


public class OkHttpManager {

    private static OkHttpClient mOkHttpClient;
    public static OkHttpClient getInstance() {
        if (mOkHttpClient == null) {
            synchronized (OkHttpManager.class) {
                if (mOkHttpClient == null) {

//                    //设置 请求的缓存
//                    File cacheFile = new File(IeouApplication.getInstance().getCacheDir(), "cache");
//                    Cache cache = new Cache(cacheFile, 1024 * 1024 * 50); //50Mb

                    mOkHttpClient = new OkHttpClient.Builder()
                            .connectTimeout(Constants.HTTP_CONNECT_TIMEOUT, TimeUnit.MILLISECONDS)
                            .readTimeout(Constants.HTTP_CONNECT_TIMEOUT, TimeUnit.MILLISECONDS)
 //                           .addInterceptor(mIntercepter)
                            .addInterceptor(new TokenInterceptor())
                            .addInterceptor(new OKHTTPLogInterceptor())
                            .addNetworkInterceptor(new HttpCacheInterceptor())
//                            .cache(cache)
                            .build();
                }
            }
        }
        return mOkHttpClient;
    }

    /**
     * 通用的请求头
     */
    private static HashMap<String, String> addHeader() {
        HashMap<String, String> header = new HashMap<>();
        header.put(Constants.HEADER_Client, PsUtils.getString(IeouApplication.getInstance(), "accessToken") == null ? Constants.FROM_ANDROID :
                PsUtils.getString(IeouApplication.getInstance(), "accessToken"));
        header.put("account_type", "CUSTOMER");
        return header;
    }

    /**
     * 拦截器 给所有的请求添加消息头
     */
    private static Interceptor mIntercepter = chain -> {

        Request.Builder builder = chain.request().newBuilder();

        HashMap<String, String> header = addHeader();

        if (header != null) {
            for (HashMap.Entry<String, String> entry : header.entrySet()) {
                builder.addHeader(entry.getKey(), entry.getValue());
            }
        }
        return chain.proceed(builder.build());
    };

  /**
     * 重新获取token
     */
    private static class TokenInterceptor implements Interceptor {

        private Handler mHandler = new Handler();
        private String resultStr;

        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request().newBuilder()
                    .header("access_token", PsUtils.getString(IeouApplication.getInstance(), "accessToken") == null ? Constants.FROM_ANDROID :
                            PsUtils.getString(IeouApplication.getInstance(), "accessToken"))
                    .header("account_type", "CUSTOMER")
                    .build();
            ;
            Response response = chain.proceed(request);
//            HashMap<String, String> header = addHeader();
//            if (header != null) {
//                for (HashMap.Entry<String, String> entry : header.entrySet()) {
//                    request.newBuilder().addHeader(entry.getKey(), entry.getValue());
//                }
//            }
            MediaType mediaType = response.body().contentType();


            if (isTokenExpired(response)) {
                //同步请求方式,获取最新的Token
                Log.e("OkHttpManager", "静默自动刷新Token,然后重新请求数据");
                //同步请求方式,获取最新的Token
                String newSession = getNewToken();
                //使用新的Token,创建新的请求
                if (null != newSession && newSession.length() > 0) {
                    Request newRequest = chain.request()
                            .newBuilder()
                            .header("access_token", newSession)
                            .header("account_type", "CUSTOMER")
                            .build();
                    //重新请求上次的接口
                    return chain.proceed(newRequest.newBuilder().build());
                }

            }
            //如果token正常返回结果
            return response.newBuilder().body(ResponseBody.create(mediaType, resultStr)).build();
        }
        /**
         * 根据Response,判断Token是否失效
         *
         * @param response
         * @return
         */
        private boolean isTokenExpired(Response response) {
            try {
                resultStr = response.body().string();
                RequestCode requestCode = new Gson().fromJson(resultStr, RequestCode.class);
                Log.e("OkHttpManager", requestCode.getResultCode() + "----requestCode");
                Log.e("OkHttpManager", resultStr + "----requestCode");
                if (requestCode.getResultCode() == 30001) {
                    Log.e("OkHttpManager", "----requestCode,Token登录过期了");
                    return true;
                }
                if (requestCode.getResultCode() == 30002) {
                    Log.e("OkHttpManager", "----requestCode,Token过期了");
                    return true;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

            return false;
        }

        String getNewToken() {
//            Call<ResponseBody> bodyCall = HttpFactory.getHttpApi().getTasks(PsUtils.getString(IeouApplication.getInstance(), "refreshToken"));
//            retrofit2.Response<ResponseBody> response = bodyCall.execute();

          /**
             * 必须使用同步请求
             */
            String url = IeouUrl.baseUrl + "user/refreshToken?refreshToken=" + PsUtils.getString(IeouApplication.getInstance(), "refreshToken");
            Log.e("OkHttpManager", "重新请求---" + url);
            OkHttpClient client = new OkHttpClient();

            Request request = new Request.Builder().url(url).build();
            okhttp3.Call call = client.newCall(request);
            try {
                Response response = call.execute();
                TokenEntity data = new Gson().fromJson(response.body().string(), TokenEntity.class);
                Log.e("OkHttpManager", "重新请求---"+data.resultCode);
                if (data.resultCode == 0) {
                    if (null != data.data.accessToken && null != data.data.refreshToken) {
                        PsUtils.putString(IeouApplication.getInstance(), "accessToken", data.data.accessToken);
                        PsUtils.putString(IeouApplication.getInstance(), "refreshToken", data.data.refreshToken);
                        PsUtils.putString(IeouApplication.getInstance(), "upToken", data.data.upToken);
                        Log.e("OkHttpManager", data.data.accessToken);
                    }
                }else {
                    mHandler.post(() -> ToastUtils.showToast("登录已过期,请重新登录..."));
                    JPushInterface.deleteAlias(IeouApplication.getInstance(), 1);
                    AppManager.getInstance().finishAllActivity();
                    MyIntent(LoginActivity.class);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }


            return PsUtils.getString(IeouApplication.getInstance(), "accessToken");
        }

        /**
         * 跳转页面
         */
        public void MyIntent(Class clazz) {
            Intent intent = new Intent(IeouApplication.getInstance(), clazz);
            intent.putExtra("fromWhere", getClass().getSimpleName());
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            IeouApplication.getInstance().startActivity(intent);
        }

    }

    /**
     * log 拦截器
     */
    private static class OKHTTPLogInterceptor implements Interceptor {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            Response response = chain.proceed(chain.request());
            okhttp3.MediaType mediaType = response.body().contentType();
            String content = response.body().string();
//            Logger.e(mediaType.toString());
            Logger.e(request.toString());
            Logger.init("json");
            Logger.json(content);

            if (response.body() != null) {
                // 打印 body 后原 ResponseBody 会被清空,需要重新设置 body
                ResponseBody body = ResponseBody.create(mediaType, content);
                return response.newBuilder().body(body).build();
            } else {
                return response;
            }
        }
    }

    /**
     * 缓存拦截器
     */
    static class HttpCacheInterceptor implements Interceptor {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            if (!NetUtils.isConnected(IeouApplication.getInstance())) {
                request = request.newBuilder()
                        .cacheControl(CacheControl.FORCE_CACHE)
                        .build();
            }

            Response originalResponse = chain.proceed(request);
            if (NetUtils.isConnected(IeouApplication.getInstance())) {
                // 有网的时候读接口上的 @Headers 里的配置,你可以在这里进行统一的设置
                String cacheControl = request.cacheControl().toString();
                return originalResponse.newBuilder()
                        .header("Cache-Control", cacheControl)
                        .removeHeader("Pragma")
                        .build();
            } else {
                return originalResponse.newBuilder()
                        .header("Cache-Control", "public, only-if-cached, max-stale=2419200")
                        .removeHeader("Pragma")
                        .build();
            }
        }
    }
}

请求接口封装

public abstract class BaseSubCallback<T> extends Subscriber<T> {
    private static final String TAG = "BaseCallback";
    private static final int CODEOK = 0;
    private static final int INLOGINSOMEWHEREELSE = 30001;
    private static final int BEOVERDUE = 30002;
    private Context mContext;
    private AlertDialog mDialog;
    private CompositeSubscription compositeSubscription = new CompositeSubscription();

    public BaseSubCallback(Context mContext) {
        this.mContext = mContext;
    }

    protected abstract void onDone(int code, String object, String msg) throws IOException;

    /**
     * 显示进度条
     */
    @Override
    public void onStart() {
        if (!NetUtils.isConnected(mContext)) {
            ToastUtils.showToast("亲,你断网了啊!");
            // 一定要调用这个方法才会生效
            onCompleted();
            return;
        }
        showProgressDialog();
//        onCompleted();
    }

    /**
     * 关闭进度条
     */
    @Override
    public void onCompleted() {
        Log.d(TAG, "onCompleted----------------");
        hideProgressDialog();

    }

    /**
     * 网络请求发生错误的处理
     *
     * @param e
     */
    @Override
    public void onError(Throwable e) {
        e.printStackTrace();
        hideProgressDialog();
        if (!NetUtils.isConnected(mContext)) {
            ToastUtils.showToast("服务器连接失败,请检查网络设置!");
            return;
        }
        ToastUtils.showToast("服务器链接超时");

    }

    /**
     * @param
     */
    @Override
    public void onNext(T responseBody) {
        Log.d(TAG, "accessToken--" + PsUtils.getString(mContext, "accessToken"));
        ResponseBody body = (ResponseBody) responseBody;
        try {
            String result = new String(body.bytes());
            Log.d("BaseonNext---------", result);
            RequestCode requestCode = new Gson().fromJson(result, RequestCode.class);
            JSONObject jsonObject = new JSONObject(result);
            if (requestCode.getResultCode() == CODEOK) {

                onDone(requestCode.getResultCode(), jsonObject.getString("data"), requestCode.getMessage());
            }
//            else if (requestCode.getResultCode() == INLOGINSOMEWHEREELSE) {//30001
//                ToastUtils.showToast("登录已过期,请重新登录...");
//            }
//            else if (requestCode.getResultCode() == BEOVERDUE) {//30002
////                ToastUtils.showToast("登录已过期,请重新登录...");
//            }
            else {
                ToastUtils.showToast(requestCode.getMessage());
                Log.e("BaseonNext---------", jsonObject.getString("data"));
            }
        } catch (IOException | JSONException e) {
            e.printStackTrace();
        }


    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,067评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,497评论 18 139
  • 宝宝,欢迎你来到这个世界! 哈,其实我知道,你早就想来到这个世界了,可是你一直找不见一个媒介,等到...
    米十七阅读 435评论 7 4
  • (三) 我觉得自己真的是个反应迟钝、后知后觉的人;从一开始我跟室友转述我们俩的对话,室友都说“我感觉...她在撩你...
    大起伏的小家伙阅读 321评论 0 0
  • 2016年即将进入倒计时,还记得那些刷屏了朋友圈的新鲜事吗?除了娱乐花边,还有社会时事。然而,最让人挪不开眼睛的,...
    创意社阅读 359评论 0 0