OKHttp拦截器做登录令牌失效基本处理

主要是讨论两个方面的问题,一是拦截器的作用和写法;二是为什么登录失效要监听HTTP的请求,如有不足,万望指出。

OKHttp的拦截器

  • 可以监听请求和响应应答,chain.proceed(request)是每个拦截器实现的关键部分。这个看似简单的方法是所有HTTP 工作发生的地方, 在这里产生一个响应应答请求.
    我们先过一下拦截器的基本写法:
OKHttpClient client =  new OKHttpClient();
client.interceptors().add(new MyInterceptor());

实现okhttp的interceptor, chain可以获取http所以请求发生的地方。

public class CityBaseInterceptor implements Interceptor{
  private static final Charset UTF8 = Charset.forName("UTF-8");
     @Override
        public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        long t1 = System.nanoTime();
        logger.info(String.format("sending request : %s on %s%n%s",   
                 request.url(),chain.connection(),request.headers()));
        RequestBody requestBody = request.body();
        Charset charset1 = UTF8;
        MediaType contentType1 = requestBody.contentType();
        if (contentType1 != null) {
            charset1 = contentType1.charset(UTF8);
        }
        String questString = requestBody.toString();
        /************/
        Log.v("yjq", String.format("sending request : %s on %s%n%s%n%s",
        request.url(),chain.connection(),request.headers(),questString));
        Response response = chain.proceed(request);
        long t2 = System.nanoTime();
        logger.info(String.format("receive request for %s in %.1fms%n%s",
                response.request().url(),(t2 - t1)/1e6d,response.headers()));

        ResponseBody responseBody = response.body();

        BufferedSource source = responseBody.source();

        source.request(Long.MAX_VALUE); // Buffer the entire body.
        Buffer buffer = source.buffer();
        Charset charset = UTF8;
        MediaType contentType = responseBody.contentType();
        if (contentType != null) {
            charset = contentType.charset(UTF8);
        }
        String bodyString = buffer.clone().readString(charset);
        Log.v("yjq","body---------->" + bodyString);
        //TODO 这里可以处理自己的业务请求,包括重新请求新的Token,获取验证信息等等。
        //showDialog();
        Log.v("yjq", String.format("receive request for %s in %.1fms%n%s",
                response.request().url(),(t2 - t1)/1e6d,response.headers()));
        return response;
    }
}

其他的应用场景为:

  1. 重写请求
    通过拦截器可以添加,移除,替换请求头。也可以改变请求的请求体。例如,在知道连接的web服务器是否支持压缩格式的情况下,可以使用应用拦截器添加请求体压缩类型。
  2. 重写响应
    相对应地,拦截器可以重写响应头和改变响应体。这一点比重写写请求头要危险,因为可能违反web服务器的期望。
    如果你处于一种比较纠结的状态,并且准备处理结果,那么重写响应头是解决问题的有效方法。例如,可以修复服务器配置错误的Cache-Control响应头是缓存更高效。

登录失效的处理

APP的用户登录如果失效,或者在其他设备上登录,我们一般通过服务器推送失效通知给设备,提醒用户保障账户安全,重新登录。
如果我们需要在请求过程中通过服务器反馈的协商好的字段来判定用户登录信息是否失效,则可以通过拦截器,并用全局的dialog提示。

  • 实现全局的dialog有几种方式,一是通过WindowManager定义宽高,并inflate自定义的view。
 final WindowManager wm = (WindowManager) MyApplication.getContext().getSystemService(Context.WINDOW_SERVICE);
        WindowManager.LayoutParams para = new WindowManager.LayoutParams();
        para.height = -1;
        para.width = -1;
        para.format = 1;

        para.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;

        para.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
        final View mView = LayoutInflater.from(MyApplication.getContext()).inflate(
                R.layout.test3, null);
        wm.addView(mView, para);

二是通过一个后台Service启动一个dialog,这个dialog需要添加一个窗口句柄:

mWindow.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

例子:

public class NewAlertDialog extends Dialog{
    private Window mWindow;
    private CloseSystemDialogsReceiver mCloseSystemDialogsReceiver;

    protected NewAlertDialog(Context context) {
        super(context);
    }

    protected NewAlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
        super(context, cancelable, cancelListener);
    }

    protected NewAlertDialog(Context context, int themeResId) {
        super(context, themeResId);
        setContentView(R.layout.token_invalid);
        mWindow = this.getWindow();
        if(mWindow != null) {
            WindowManager.LayoutParams attributes = mWindow.getAttributes();
//        attributes.width = mWindow.getWindowManager().getDefaultDisplay()
//                .getWidth();
            attributes.width = WindowManager.LayoutParams.WRAP_CONTENT;
            attributes.height = WindowManager.LayoutParams.WRAP_CONTENT;
            mWindow.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

            IntentFilter filter = new IntentFilter(
                    Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
            mCloseSystemDialogsReceiver = new CloseSystemDialogsReceiver();
            mWindow.getContext().registerReceiver(mCloseSystemDialogsReceiver,
                    filter);
        }
    }

    private class CloseSystemDialogsReceiver extends BroadcastReceiver {
        final String SYSTEM_DIALOG_REASON_KEY = "reason";
        final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";

        @Override
        public void onReceive(Context context, Intent intent) {
            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
                String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
                if (SYSTEM_DIALOG_REASON_HOME_KEY.equals(reason)) {
                    NewAlertDialog.this.dismiss();          
            
   mWindow.getContext().unregisterReceiver(mCloseSystemDialogsReceiver);
getContext().stopService(new Intent(getContext(),WindowDialogService.class));
                }
            }
        }
    }
}

其中CloseSystemDialogsReceiver是处理SYSTEM.ALERT的dialog点击Home键无法消失的问题。

你可能感兴趣的:(OKHttp拦截器做登录令牌失效基本处理)