之前在面試的時候遇到這樣的一個問題,那就是如果app中所有的請求都要加入一些參數(例如 版本號、手機號、登錄用戶名、token等。。。)那么怎么做才能實現,而不至于在每次請求的時候都去進行添加這些請求頭。其實這個問題,剛開始我是拒絕的(之前沒有遇到過這樣的需求)。當時只是想著可以使用okhttp體用的攔截器Interceptor來進行實現,但是具體的實現還是來到了今天。
在okhttp-wiki里面專門有一篇介紹Interceptor的(點擊我跳轉到Interceptor鏈接)里面有這樣的一句話
Interceptors are a powerful mechanism that can monitor, rewrite, and retry calls. 攔截器是一種強大的機制,可以監視、重寫和重試調用
具體的作用簡介這里不再贅述,這里推薦一篇翻譯的文章(Okhttp-wiki 之 Interceptors 攔截器)
先來看下我們的需求
2、客戶端請求API的數據格式為json形式:
{ "publicParams":{}, "key1":value, "key2":value}其中publicParams為公共參數,每個API接口必須傳遞
3、公共參數
| 字段 | 類型 | 說明 | 
|---|---|---|
| imei | string | 移動設備身份(非必須) | 
| model | 手機型號、設備名稱 | |
| la | string | 系統語言 | 
| resolution | string | 分辨率(格式:1920*1080) | 
| densityScaleFactor | string | 密度比例 | 
| sdk | int | SDK版本號 | 
| os | string | 系統源代碼控制值 | 
我們就是利用Interceptor攔截器,對每次的網絡請求進行攔截,然后拿到請求url,并對url進行改造來加入我們需要的公共參數,進行和請求參數的拼接,然后構造request,通過chain.PRoceed(request)進行改造。
   這里我們只需要用到url()方法(主要獲取到api地址和請求參數,并進行改造),用到method()方法來判斷get請求和post請求。   這個時候我們看下代碼怎么進行編寫吧。     @Override    public Response intercept(Chain chain) throws IOException {        //獲取到request        Request request = chain.request();        //獲取到方法        String method = request.method();        //公共參數hasmap        try {            //添加公共參數            HashMap<String, Object> commomParamsMap = new HashMap<>();            commomParamsMap.put(Constants.IMEI, DeviceUtils.getIMEI(mContext));            commomParamsMap.put(Constants.MODEL, DeviceUtils.getModel());            commomParamsMap.put(Constants.LANGUAGE, DeviceUtils.getLanguage());            commomParamsMap.put(Constants.os, DeviceUtils.getBuildVersionIncremental());            commomParamsMap.put(Constants.RESOLUTION, DensityUtil.getScreenW(mContext) + "*" + DensityUtil.getScreenH(mContext));            commomParamsMap.put(Constants.SDK, DeviceUtils.getBuildVersionSDK() + "");            commomParamsMap.put(Constants.DENSITY_SCALE_FACTOR, mContext.getResources().getDisplayMetrics().density + "");            //get請求的封裝            if (method.equals("GET")) {                //獲取到請求地址api                HttpUrl httpUrlurl = request.url();                HashMap<String, Object> rootMap = new HashMap<>();                //通過請求地址(最初始的請求地址)獲取到參數列表                Set<String> parameterNames = httpUrlurl.queryParameterNames();                for (String key : parameterNames) {  //循環參數列表                    if (Constants.PARM.equals(key)) {  //判斷是否有匹配的字段  這個類似于  /xxx/xxx?p={}  匹配這個p                        String oldParamsJson = httpUrlurl.queryParameter(Constants.PARM);                        if (oldParamsJson != null) {  //因為有的是沒有這個p={"page":0}  而是直接/xxx/index的                            HashMap<String, Object> p = mGson.fromJson(oldParamsJson, HashMap.class);  //原始參數                            if (p != null) {                                for (Map.Entry<String, Object> entry : p.entrySet()) {                                    rootMap.put(entry.getKey(), entry.getValue());                                }                            }                        }                    } else {                        rootMap.put(key, httpUrlurl.queryParameter(key));                    }                }                //String oldParamJson = httpUrlurl.queryParameter(Constants.PARM);//            if (oldParamJson != null) {////            }                //把原來請求的和公共的參數進行組裝                rootMap.put("publicParams", commomParamsMap);  //重新組裝                String newJsonParams = mGson.toJson(rootMap);  //裝換成json字符串                String url = httpUrlurl.toString();                int index = url.indexOf("?");                if (index > 0) {                    url = url.substring(0, index);                }                url = url + "?" + Constants.PARM + "=" + newJsonParams;  //拼接新的url                request = request.newBuilder().url(url).build();  //重新構建請求                //post請求的封裝            } else if (method.equals("POST")) {//           FormBody.Builder builder = new FormBody.Builder();//            builder.addEncoded("phone","phone");                RequestBody requestBody = request.body();                HashMap<String, Object> rootMap = new HashMap<>();                if (requestBody instanceof FormBody) {                    for (int i = 0; i < ((FormBody) requestBody).size(); i++) {                        rootMap.put(((FormBody) requestBody).encodedName(i), ((FormBody) requestBody).encodedValue(i));                    }                } else {                    //buffer流                    Buffer buffer = new Buffer();                    requestBody.writeTo(buffer);                    String oldParamsJson = buffer.readUtf8();                    rootMap = mGson.fromJson(oldParamsJson, HashMap.class);  //原始參數                    rootMap.put("publicParams", commomParamsMap);  //重新組裝                    String newJsonParams = mGson.toJson(rootMap);  //裝換成json字符串                    request = request.newBuilder().post(RequestBody.create(JSON, newJsonParams)).build();                }            }        } catch (JsonSyntaxException e) {            e.printStackTrace();        }        //最后通過chain.proceed(request)進行返回        return chain.proceed(request);    }當我們把自定義的Interceptor構建完成之后,我們需要在Okhttp中進行使用。
return new OkHttpClient.Builder() //HeadInterceptor 實現了Intercepter 用來網Request Header添加一些相關數據 如APP版本 token信息// .addInterceptor(new HttpLoggingInterceptor()) //添加自定義的攔截器,完成公共參數的封裝 .addInterceptor(new CommonParamsInterceptor(gson,application)) .connectTimeout(10, TimeUnit.SECONDS)//鏈接超時 .readTimeout(10, TimeUnit.SECONDS)//設置讀取超時 .build();這個時候就可以了,我們來看下攔截之前和加入攔截器之后的請求url,看看是否起到了作用。 這個時候我們debug一下看下就明白了。 我們可以看到下圖中上面的參數是只有一個,但是第二行就已經改變了,添加過了我們需要的公共參數,并且還有我們請求的參數。符合我們的要求。 
Okhttp-wiki 之 Interceptors 攔截器 Okhttp-wiki之Interceptors
新聞熱點
疑難解答