OkHttp3拦截器通用参数配置

OkHttp3网络请求库相信大家都用起来了,通用请求参数配置每个App都会有,例如登录后,必传Token令牌,UserId用户Id等。

本篇记录一下自己封装的请求时带通用请求参数的配置,也是对Json上传的请求做通用参数配置时遇到的问题和解决方案。

封装思想

常用请求方式分为GET表单请求、POST表单请求、POST上传JSON请求,所以拦截器就对这3种进行适配,如果需要其他的请求方式,再做对应的拦截器即可。

3种请求方式,就要写3个拦截器,3个拦截器,我觉得有些冗余,其实1个就够了。拦截器就是责任链模式的应用,请求调用时,遍历拦截器链,每个拦截器都有机会处理。那么我们可以做一个统一的拦截器作为分发,内部做3个处理器再做责任链遍历处理。原理就是如此,撸起袖子就是干!

使用

使用就一句代码即可!

val builder = OkHttpClient.Builder()
//对你的OkHttpClient的Builder进行处理
val builder = builder.apply {
    //配置这句即可
    RequestProcessor.getInstance().with(this)
}
//OkGo配置OkHttpClient,如果你是用其他框架,将builder传框架即可
OkGo.getInstance().init(this)
    .setOkHttpClient(builder.build())

类结构

类有5个,1个OkHttp拦截器类,1个请求处理者抽象接口

  • RequestProcessor,请求处理器,内含一个OkHttp拦截器,以及3个请求处理者。负责拦截请求,分发请求到注册的处理者。

  • RequestProcessHandler,处理者抽象接口,有2个方法,isCanHandle(request)判断请求是否可以处理,process(request)处理方法。

3个不同请求方式的自定义处理者

  • GetRequestHandler,GET表单请求方式的处理者,负责拦截GET表单请求,并且添加参数。

  • FormPostRequestHandler,POST表单请求方式的处理者,负责拦截POST表单请求,并且添加参数。

  • JsonPostRequestHandler,POST上传JSON请求方式的处理者,负责拦截POST上传JSON的请求,并对JSON添加公用参数。

代码实现

GET、POST的表单请求比较简单,OkHttp3都提供了获取方法和对应Builder类。遇到问题的是POST上传JSON添加公共参数的问题,官方并没有Api提供。

  • RequestProcessor请求处理器。

    1. 单例,私有化构造方法,提供getInstance()方法获取单例。
    2. 提供with()方法,提供给外部传入OkHttpClient的Builder,我们添加完拦截器后返回
    3. 提供setEnable(enable)设置是否启动,isEnable()判断是否启用
    4. 提供registerProcessHandler()方法,支持外部注册请求处理者
    5. 提供unregisterProcessHandler()方法,支持外部解注册请求处理者
    6. 内部默认添加3种处理者
class RequestProcessor private constructor() {
    /**
     * 是否启用,默认启用
     */
    private var isEnable = true
    /**
     * 统一分发的拦截器
     */
    private var mDispatchInterceptor: Interceptor
    /**
     * 处理器链
     */
    private val mProcessHandlerChain by lazy {
        CopyOnWriteArrayList<RequestProcessHandler>()
    }

    companion object {
        private class SingleHolder {
            companion object {
                val INSTANCE: RequestProcessor = RequestProcessor()
            }
        }

        fun getInstance(): RequestProcessor {
            return SingleHolder.INSTANCE
        }
    }

    init {
        //注册多种请求处理器
        registerProcessHandler(GetRequestHandler())
        registerProcessHandler(FormPostRequestHandler())
        registerProcessHandler(JsonPostRequestHandler())
        //初始化分发拦截器
        this.mDispatchInterceptor = Interceptor { chain ->
            if (!isEnable) {
                chain.proceed(chain.request())
            } else {
                chain.proceed(processRequest(chain.request()))
            }
        }
    }

    /**
     * 处理请求
     */
    private fun processRequest(originRequest: Request?): Request {
        var outRequest: Request = originRequest!!
        //责任链分派给不同的请求处理器
        mProcessHandlerChain.forEach { handler ->
            //可以处理,就给对应的处理器处理
            if (handler.isCanHandle(originRequest)) {
                outRequest = handler.process(originRequest)
                return@forEach
            }
        }
        return outRequest
    }

    /**
     * 提供给外部传入OkHttpClient的Builder,我们添加完拦截器后返回
     */
    fun with(builder: OkHttpClient.Builder): OkHttpClient.Builder {
        return builder.addInterceptor(mDispatchInterceptor)
    }

    /**
     * 是否启用
     */
    fun isEnable(): Boolean {
        return this.isEnable
    }

    /**
     * 设置是否启动
     */
    fun setEnable(enable: Boolean) {
        this.isEnable = enable
    }

    /**
     * 注册请求处理器
     */
    fun registerProcessHandler(handler: RequestProcessHandler) {
        if (!mProcessHandlerChain.contains(handler)) {
            mProcessHandlerChain.add(handler)
        }
    }

    /**
     * 解注册请求处理器
     */
    fun unregisterProcessHandler(handler: RequestProcessHandler) {
        mProcessHandlerChain.remove(handler)
    }
}
  • RequestProcessHandler,请求处理者抽象接口,定义2个抽象方法。
interface RequestProcessHandler {
    /**
     * 是否可以处理
     * @return 返回true代表可以处理,返回false代表不可以处理
     */
    fun isCanHandle(originRequest: Request): Boolean

    /**
     * 处理
     * @param originRequest 原始的请求
     * @return 处理过后的请求
     */
    fun process(originRequest: Request): Request
}
  • GetRequestHandler,GET表单请求者。

    1. isCanHandle()方法,判断请求的方式是否是GET,否则不处理
    2. process()方法,处理本次的GET表单请求,处理Header。Header添加参数,重新创建Headers.Builder,再将原始Header参数添加即可。
    3. 最后将新的header,重新设置。
class GetRequestHandler : RequestProcessHandler {
    override fun isCanHandle(originRequest: Request): Boolean {
        return "GET" == originRequest.method()
    }

    override fun process(originRequest: Request): Request {
        val loginService = getLoginService()
        val token = loginService?.getToken() ?: ""
        val userId = loginService?.getUserId() ?: ""
        //原始Header
        val originHeaders = originRequest.headers()
        //增加公共Header
        val newHeaders = Headers.Builder()
            //先添加原有Header
            .addAll(originHeaders).apply {
                //平台标识
                add(AppConstant.HttpParameter.PLATFORM, ApiUrl.PLATFORM)
                //增加公共参数
                if (token.isNotBlank()) {
                    //调用方没有加相同的公共参数时,才添加,避免在切换的业务场景时覆盖
                    val key = AppConstant.HttpParameter.TOKEN
                    if (originHeaders.get(key).isNullOrBlank()) {
                        add(key, token)
                        LogUtils.d("JSON POST => 添加公共参数 -> $key : $token")
                    }
                }
                if (userId.isNotBlank()) {
                    val key = AppConstant.HttpParameter.USER_ID
                    if (originHeaders.get(key).isNullOrBlank()) {
                        add(key, userId)
                        LogUtils.d("JSON POST => 添加公共参数 -> $key : $userId")
                    }
                }
            }
            .build()
        return originRequest.newBuilder()
            //设置Header
            .headers(newHeaders)
            .build()
    }
}
  • FormPostRequestHandler,处理Post请求是表单提交

    1. isCanHandle()方法中判断请求的body对象是否是FormBody,否则不处理,如果是,则在process()方法中进行处理。
    2. 设置公共参数到Header,最后重新配置Header到请求中。
class FormPostRequestHandler : RequestProcessHandler {
    override fun isCanHandle(originRequest: Request): Boolean {
        val body = originRequest.body()
        if (body is FormBody) {
            return true
        } else if (body is ProgressRequestBody<*>) {
            //这里是处理OkGo对FormBody的包装,如果你不是用OkGo框架,则不需要这句判断
            return try {
                //反射获取包装的RequestBody
                val newBody: RequestBody = Reflect.on(body).field("requestBody").get()
                newBody is FormBody
            } catch (e: Exception) {
                false
            }
        }
        return false
    }

    override fun process(originRequest: Request): Request {
        //公共参数
        val loginService = getLoginService()
        val token = loginService?.getToken() ?: ""
        val userId = loginService?.getUserId() ?: ""
        //原始Header
        val originHeaders = originRequest.headers()
        //增加公共Header
        val newHeaders = Headers.Builder()
            //先添加原有Header
            .addAll(originHeaders).apply {
                //平台标识
                add(AppConstant.HttpParameter.PLATFORM, ApiUrl.PLATFORM)
                //增加公共参数
                if (token.isNotBlank()) {
                    val key = AppConstant.HttpParameter.TOKEN
                    if (originHeaders.get(key).isNullOrBlank()) {
                        add(key, token)
                        LogUtils.d("JSON POST => 添加公共参数 -> $key : $token")
                    }
                }
                if (userId.isNotBlank()) {
                    val key = AppConstant.HttpParameter.USER_ID
                    if (originHeaders.get(key).isNullOrBlank()) {
                        add(key, userId)
                        LogUtils.d("JSON POST => 添加公共参数 -> $key : $userId")
                    }
                }
            }
            .build()
        return originRequest.newBuilder()
            //设置Header
            .headers(newHeaders)
            .build()
    }
}
  • JsonPostRequestHandler,处理Json上传请求

    1. isCanHandle()方法中判断请求的body对象是否是RequestBody,否则不处理,如果是,则在process()方法中进行处理。
    2. 设置公共参数到Header,最后重新配置Header到请求中。
class JsonPostRequestHandler : RequestProcessHandler {
    override fun isCanHandle(originRequest: Request): Boolean {
        return originRequest.body() is RequestBody
    }

    override fun process(originRequest: Request): Request {
        //原始Header
        val originHeaders = originRequest.headers()
        val newHeaders = originRequest.headers().newBuilder().apply {
            //增加公共参数
            val loginService = getLoginService()
            val token = loginService?.getToken() ?: ""
            val userId = loginService?.getUserId() ?: ""
            //平台标识
            add(AppConstant.HttpParameter.PLATFORM, ApiUrl.PLATFORM)
            //Token令牌
            if (token.isNotBlank()) {
                val key = AppConstant.HttpParameter.TOKEN
                if (originHeaders.get(key).isNullOrBlank()) {
                    add(key, token)
                    LogUtils.d("JSON POST => 添加公共参数 -> $key : $token")
                }
            }
            //用户Id
            if (userId.isNotBlank()) {
                val key = AppConstant.HttpParameter.USER_ID
                if (originHeaders.get(key).isNullOrBlank()) {
                    add(key, userId)
                    LogUtils.d("JSON POST => 添加公共参数 -> $key : $userId")
                }
            }
        }
            .build()
        return originRequest.newBuilder()
            //设置Header
            .headers(newHeaders)
            .build()
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,688评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,559评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,749评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,581评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,741评论 3 271
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,684评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,122评论 2 292
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,847评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,441评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,939评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,333评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,783评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,275评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,830评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,444评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,553评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,618评论 2 249

推荐阅读更多精彩内容