OkHttp 攔截器的一些騷操作

前言

怎么說呢,幾個月沒寫博客,時過境遷,也斷了那種感覺。一個好的習慣需要27天的周期才能養(yǎng)成,要放棄一個習慣那不需要周期,懶就可以。主要也沒有好的內(nèi)容要向廣大基友來傳播,這也省了大家的閱讀時間 去刷抖音了hhhh,不說了 進入主題

騷操作目錄

也就不廢話了,可以看到下面的目錄,有哪些騷操作 ,希望可以幫助日常開發(fā)中的小伙伴們。

  1. URL重定向
  2. 請求體數(shù)據(jù)加密
  3. HEAD動態(tài)添加
  4. 請求日志抓取

URL重定向

如何重定向,說白了就是更換個新的url,但是一般服務端做比較好,客戶端就顯得有些雞肋。但是這個東西日常也會有用到,比如一些場景,測試生成環(huán)境的切換。業(yè)務多了,幾個人混合開發(fā)的后臺,每個人的代碼不同意導致了baseurl還不同,這時候可以通過一個入口來修改就行,不然每個地方都去修改,接口量大的話會很麻煩。

  • 自定義一個Interceptor(TestInterceptor后面都是基于這個來講解),直接創(chuàng)建個類實現(xiàn)Interceptor接口即可,然后在Okhttp初始化的是添加這個攔截器即可
public class TestInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {

        return null;
    }
}

然后在你需要初始化的okhttp的地方添加這個攔截器

public class TestActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        OkHttpClient build = new OkHttpClient.Builder()
                .addInterceptor(new TestInterceptor())
                .build();
    }
}

那么接下來我們需要干什么呢,攔截器已經(jīng)寫好了,既然定義是攔截器,肯定請求體信息都在那里。我們可以在接口Interceptor里面的方法intercept給了我們一個參數(shù)Chain,一切的源頭都在這里面。來看看接下來如何進行騷操作來改變初始的URL達到重定向的功能


public class TestInterceptor implements Interceptor {
    private String newHost = "127.0.0.1";
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        HttpUrl url = request.url();
        //http://127.0.0.1/test/upload/img?userName=xiaoming&userPassword=12345
        String scheme = url.scheme();//  http https
        String host = url.host();//   127.0.0.1
        String path = url.encodedPath();//  /test/upload/img
        String query = url.encodedQuery();//  userName=xiaoming&userPassword=12345

        StringBuffer sb = new StringBuffer();
        String newUrl = sb.append(scheme).append(newHost).append(path).append("?").append(query).toString();

        Request.Builder builder = request.newBuilder()
                .url(newUrl);

        return chain.proceed(builder.build());
    }
}

上面只是簡單的換了一下host retrofit可以輕易做到,在構(gòu)造retrofit的時候可以修改baseUrl,但是如果要換path呢,這時候可能retrofit不是那么好做,而且你需要每個地方都要換,這時候你可以在這里當成一個統(tǒng)一的入口new一個新的path即可。簡單吧,對于后面的每個字段說明意思我在后面也有備注,可以看到拆分后的樣子

請求體數(shù)據(jù)加密

既然要對請求體加密,那肯定要知道請求體在哪里,然后才能加密,其實都一樣不論是加密url里面的query內(nèi)容還是加密body體里面的都一樣,只要拿到了對應的數(shù)據(jù)我們想怎么做怎么,有的接口比較奇葩,他需要根據(jù)請求體的內(nèi)容進行簽名認證。不論如何我們拿到了請求體當然想怎么樣就怎么樣,看下嘛的操作

  1. 加密query內(nèi)容
public class TestInterceptor implements Interceptor {
    private String newHost = "127.0.0.1";

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        HttpUrl url = request.url();

        //http://127.0.0.1/test/upload/img?userName=xiaoming&userPassword=12345
        String scheme = url.scheme();//  http https
        String host = url.host();//   127.0.0.1
        String path = url.encodedPath();//  /test/upload/img
        String query = url.encodedQuery();//  userName=xiaoming&userPassword=12345

        StringBuffer sb = new StringBuffer();
        sb.append(scheme).append(newHost).append(path).append("?");
        Set<String> queryList = url.queryParameterNames();
        Iterator<String> iterator = queryList.iterator();
        
        for (int i = 0; i < queryList.size(); i++) {
            
            String queryName = iterator.next();
            sb.append(queryName).append("=");
            String queryKey = url.queryParameter(queryName);
            //對query的key進行加密
            sb.append(CommonUtils.getMD5(queryKey));
            if (iterator.hasNext()) {
                sb.append("&"); 
            }
        }


        String newUrl = sb.toString();

        Request.Builder builder = request.newBuilder()
                .url(newUrl);

        return chain.proceed(builder.build());
    }
}

這樣拼接的query內(nèi)容就可以直接統(tǒng)一加密了。我這里只是簡單的md5加密 如果說服務端和客戶端定義了一套加密解密協(xié)議,就可以在這里進行特定的加密方式進行加密

  1. 加密body體內(nèi)容

public class TestInterceptor implements Interceptor {
    private String newHost = "127.0.0.1";


    public static String requestBodyToString(RequestBody requestBody) throws IOException {
        Buffer buffer = new Buffer();
        requestBody.writeTo(buffer);
        return buffer.readUtf8();
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        HttpUrl url = request.url();

        //http://127.0.0.1/test/upload/img?userName=xiaoming&userPassword=12345
        String scheme = url.scheme();//  http https
        String host = url.host();//   127.0.0.1
        String path = url.encodedPath();//  /test/upload/img
        String query = url.encodedQuery();//  userName=xiaoming&userPassword=12345

        StringBuffer sb = new StringBuffer();
        sb.append(scheme).append(newHost).append(path).append("?");
        Set<String> queryList = url.queryParameterNames();
        Iterator<String> iterator = queryList.iterator();

        for (int i = 0; i < queryList.size(); i++) {

            String queryName = iterator.next();
            sb.append(queryName).append("=");
            String queryKey = url.queryParameter(queryName);
            //對query的key進行加密
            sb.append(CommonUtils.getMD5(queryKey));
            if (iterator.hasNext()) {
                sb.append("&");
            }
        }


        String newUrl = sb.toString();


        RequestBody body = request.body();
        String bodyToString = requestBodyToString(body);
        TestBean testBean = GsonTools.changeGsonToBean(bodyToString, TestBean.class);
        String userPassword = testBean.getUserPassword();
        //加密body體中的用戶密碼
        testBean.setUserPassword(CommonUtils.getMD5(userPassword));
        
        String testGsonString = GsonTools.createGsonString(testBean);
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), testGsonString);
        


        Request.Builder builder = request.newBuilder()
                .post(requestBody)
                .url(newUrl);

        return chain.proceed(builder.build());
    }
}

從上面可以看出我們先拿到body體的內(nèi)容然后解析后,拿到對應的實體類,然后進行加密,再次創(chuàng)建一個新的body體里面然后post過去,即可達到body體加密,我這只是一種body加密方法,也有可能是拿到body然后進行加密然后對加密后的東西加入head 當成簽名使用。

最終這種攔截器方式的加密也是一種統(tǒng)一代碼入口的方式。

HEAD動態(tài)添加

在日常的開發(fā)中,可能每個接口對應的header不同有的多有的少。不可能說每個接口都寫一個攔截器進行添加頭部。這時候我們可以換個思維來考慮這個問題。怎么做呢,其實也是為了統(tǒng)一代碼,同一種操作不要再多個地方進行,這樣修改起來很麻煩。統(tǒng)一入口,統(tǒng)一出口。


public class TestInterceptor implements Interceptor {
    private String newHost = "127.0.0.1";
    private String path1 = "/test/upload/img";
    private String path2 = "/test/upload/voice";

    public static String requestBodyToString(RequestBody requestBody) throws IOException {
        Buffer buffer = new Buffer();
        requestBody.writeTo(buffer);
        return buffer.readUtf8();
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        HttpUrl url = request.url();

        //http://127.0.0.1/test/upload/img?userName=xiaoming&userPassword=12345
        String scheme = url.scheme();//  http https
        String host = url.host();//   127.0.0.1
        String path = url.encodedPath();//  /test/upload/img
        String query = url.encodedQuery();//  userName=xiaoming&userPassword=12345

        StringBuffer sb = new StringBuffer();
        sb.append(scheme).append(newHost).append(path).append("?");
        Set<String> queryList = url.queryParameterNames();
        Iterator<String> iterator = queryList.iterator();

        for (int i = 0; i < queryList.size(); i++) {

            String queryName = iterator.next();
            sb.append(queryName).append("=");
            String queryKey = url.queryParameter(queryName);
            //對query的key進行加密
            sb.append(CommonUtils.getMD5(queryKey));
            if (iterator.hasNext()) {
                sb.append("&");
            }
        }


        String newUrl = sb.toString();


        RequestBody body = request.body();
        String bodyToString = requestBodyToString(body);
        TestBean testBean = GsonTools.changeGsonToBean(bodyToString, TestBean.class);
        String userPassword = testBean.getUserPassword();
        //加密body體中的用戶密碼
        testBean.setUserPassword(CommonUtils.getMD5(userPassword));

        String testGsonString = GsonTools.createGsonString(testBean);
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), testGsonString);
        
        Request.Builder builder = request.newBuilder()
                .post(requestBody)
                .url(newUrl);

        switch (path) {
            case path1:
                builder.addHeader("token","token");
                break;
            case path2:
                builder.addHeader("token","token");
                builder.addHeader("uid","uid");
                break;
        }


    


        return chain.proceed(builder.build());
    }
}


騷不騷,根據(jù)url中path的不同來動態(tài)的添加header,其實寫代碼嗎?每個人實現(xiàn)的方式不同,只要路子對,怎么擼都行,看個人。

請求日志抓取

這個其實已經(jīng)有現(xiàn)成的log攔截器了,大家日常開發(fā)中已經(jīng)有用過,但是如果說我們只想看到我想要的,過濾那些不要的東西。怎么辦呢。只能自己來自定義了。把自己需要的東西打印出來。以免太多每次看很亂。這時候怎么通過攔截器完成這樣的一個騷操作呢。也很簡單,基于上面的基礎(chǔ)我們應該該拿到的都拿到了。


public class TestInterceptor implements Interceptor {
    private String newHost = "127.0.0.1";
    private String path1 = "/test/upload/img";
    private String path2 = "/test/upload/voice";
    private String TAG = "TestInterceptor";
    public static String requestBodyToString(RequestBody requestBody) throws IOException {
        Buffer buffer = new Buffer();
        requestBody.writeTo(buffer);
        return buffer.readUtf8();
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Response response = chain.proceed(request);
        
        HttpUrl url = request.url();
        //http://127.0.0.1/test/upload/img?userName=xiaoming&userPassword=12345
        String scheme = url.scheme();//  http https
        String host = url.host();//   127.0.0.1
        String path = url.encodedPath();//  /test/upload/img
        String query = url.encodedQuery();//  userName=xiaoming&userPassword=12345
        
        RequestBody body = request.body();
        String bodyToString = requestBodyToString(body);

        
        
        Log.e(TAG,scheme);
        Log.e(TAG,host);
        Log.e(TAG,path);
        Log.e(TAG,query);

        if (response != null) {
            ResponseBody responseBody = response.body();
            long contentLength = responseBody.contentLength();
            String bodySize = contentLength != -1 ? contentLength + "-byte" : "unknown-length";
            
            Log.e(TAG,response.code() + ' ' 
                    + response.message() + ' '
                    + response.request().url()+' '
                    + bodySize
                 );

            Headers headers = response.headers();
            for (int i = 0, count = headers.size(); i < count; i++) {
                Log.e(TAG,headers.name(i) + ": " + headers.value(i));
            }
            
            
        }
        
        


        return chain.proceed(request);
    }
}

根據(jù)自己的需求來吧,我只是簡單的打印一些東西。也是基于上面的代碼來的。

ending

花了個把小時寫的東西,希望給老鐵們帶來的是知識的儲備而不是時間的浪費。不早了不早了下班了,

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容