OkHttp3網絡請求(二)之攔截器

OkHttp3網絡請求上一篇已經簡單介紹了,之前看鴻洋大神的博客學習OkHttp的使用,這裏記錄一下學習成果。

關於攔截器的介紹這裏就不介紹了,直接使用:

RequestInterceptor.java

public class RequestInterceptor implements Interceptor {

    /**
     * headerLines 參數List
     */
    private List<String> headerLinesList = new ArrayList<>();
    /**
     * header 參數Map
     */
    private Map<String, String> headerParamsMap = new HashMap<>();
    /**
     * url 參數Map
     */
    private Map<String, String> urlParamsMap = new HashMap<>();
    /**
     * body 參數Map   來自於 {@link OkParamsInject}
     */
    private Map<String, String> bodyParamsMap = new HashMap<>();
    /**
     * 加入動態參數
     */
    private DynamicParams dynamicParams;
    /**
     * 提交的是否是Json數據
     */
    private boolean isJson;

    private RequestInterceptor(boolean isJson) {
        this.isJson = isJson;
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Request.Builder requestBuilder = request.newBuilder().addHeader("Connection", "close");

        ///////////////////////////////////////////////////////////////////////////
        // process header params inject
        ///////////////////////////////////////////////////////////////////////////
        Headers.Builder headerBuilder = request.headers().newBuilder();
        if (headerLinesList.size() > 0) {
            for (String line : headerLinesList) {
                headerBuilder.add(line);
            }
        }
        if (headerParamsMap.size() > 0) {
            for (Map.Entry entry : headerParamsMap.entrySet()) {
                headerBuilder.add((String) entry.getKey(), (String) entry.getValue());
            }
        }
        requestBuilder.headers(headerBuilder.build());

        ///////////////////////////////////////////////////////////////////////////
        // process url params inject whatever it's GET or POST
        ///////////////////////////////////////////////////////////////////////////
        if (urlParamsMap.size() > 0) {
            injectParamsIntoUrl(request, requestBuilder, urlParamsMap);
        }

        ///////////////////////////////////////////////////////////////////////////
        // process body params inject
        ///////////////////////////////////////////////////////////////////////////
        if (request.method().equals("POST")) {
            RequestBody body = request.body();
            // POST上傳文件 
            if (body instanceof MultipartBody) {
                StringBuilder stringBuilder = new StringBuilder();
                if (bodyParamsMap.size() > 0) {
                    for (Map.Entry entry : bodyParamsMap.entrySet()) {
                        stringBuilder.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
                    }
                }
                String postBodyString = stringBuilder.toString().substring(0, stringBuilder.toString().length() - 1);
相同
                if (null != dynamicParams) {
                    HttpUrl url = request.url();
                    String route = url.toString().replace(UrlUtil.host, "");
                    if (rout兩次e.contains("?")) {
                        route = route.substring(0, route.indexOf("?"));
                    }
                    // 此處把已有參數傳到dynamicParams中,可以做一些簽名加密添加動態參數等操作,最終返回key1=value1&key2=value2&...	下面
                    postBodyString = dynamicParams.signParams(postBodyString, request.method(), route);
                }

                MultipartBody.Builder newMultipartBodyBuilder = new MultipartBody.Builder();
                newMultipartBodyBuilder.setType(MultipartBody.FORM);
                // 最終參數作爲form參數放到MultipartBody
                TreeMap<String, String> treeMap = splitPostString(postBodyString);
                for (Map.Entry entry : treeMap.entrySet()) {
                    newMultipartBodyBuilder.addFormDataPart((String) entry.getKey(), (String) entry.getValue());
                }

                // File可以不參與簽名,最後把File作爲part參數放到MultipartBody中
                for (MultipartBody.Part part : ((MultipartBody) request.body()).parts()) {
                    newMultipartBodyBuilder.addPart(part);
                }

                requestBuilder.post(newMultipartBodyBuilder.build());
            } else {
            	// 一般POST請求
                FormBody.Builder formBodyBuilder = new FormBody.Builder();
                // add new params to new formBodyBuilder
                if (bodyParamsMap.size() > 0) {
                    for (Map.Entry entry : bodyParamsMap.entrySet()) {
                        formBodyBuilder.add((String) entry.getKey(), (String) entry.getValue());
                    }
                }
                // add old params to new formBodyBuilder
                FormBody formBody = formBodyBuilder.build();
                String postBodyString = bodyToString(request.body());

                postBodyString += ((postBodyString.length() > 0) ? "&" : "") + bodyToString(formBody);

                if (null != dynamicParams) {
                    HttpUrl url = request.url();
                    String route = url.toString().replace(UrlUtil.host, "");
                    if (route.contains("?")) {
                        // /api/goods/sale/list?o=hot 類似這樣的需要把問號後面的去掉
                        route = route.substring(0, route.indexOf("?"));
                    }
                    postBodyString = dynamicParams.signParams(postBodyString, request.method(), route);
                }
                if (isJson) {
                    Gson gson = new Gson();
                    Map<String, String> stringMap = new HashMap<>();
                    for (String value : postBodyString.split("&")) {
                        stringMap.put(value.split("=")[0], value.split("=")[1]);
                    }
                    postBodyString = gson.toJson(stringMap);
                }
                requestBuilder.post(RequestBody.create(formBody.contentType(), postBodyString));
            }
        } else {// GET
            FormBody.Builder formBodyBuilder = new FormBody.Builder();
            if (bodyParamsMap.size() > 0) {
                for (Map.Entry entry : bodyParamsMap.entrySet()) {
                    formBodyBuilder.add((String) entry.getKey(), (String) entry.getValue());
                }
            }

            HttpUrl httpUrl = request.url();
            Set<String> queryKeys = httpUrl.queryParameterNames();
            for (String key : queryKeys) {
                String value = httpUrl.queryParameter(key);
                if (value != null) formBodyBuilder.add(key, value);
            }

            FormBody formBody = formBodyBuilder.build();
            String postBodyString = bodyToString(request.body());

            postBodyString += ((postBodyString.length() > 0) ? "&" : "") + bodyToString(formBody);
            postBodyString = URLDecoder.decode(postBodyString, "utf8");
            if (null != dynamicParams) {
                HttpUrl url = request.url();
                String route = url.toString().replace(UrlUtil.host, "");
                if (route.contains("?")) {
                    // /api/goods/sale/list?o=hot 類似這樣的需要把問號後面的去掉
                    route = route.substring(0, route.indexOf("?"));
                }
                postBodyString = dynamicParams.signParams(postBodyString, request.method(), route);
            }
            Gson gson = new Gson();
            Map<String, String> stringMap = new HashMap<>();
            for (String value : postBodyString.split("&")) {
                String[] split = value.split("=");
                stringMap.put(split[0], split.length > 1 ? split[1] : "");
            }

            // if can't inject into body, then inject into url
            injectParamsIntoUrl(request, requestBuilder, stringMap);
            // injectParamsIntoUrl(request, requestBuilder, bodyParamsMap);
        }

        request = requestBuilder.build();

        Response originalResponse = chain.proceed(request);
        Response priorResponse = originalResponse.priorResponse();
        // 如果是重定向,那麼就執行重定向請求後再返回數據。
        if (null != priorResponse && priorResponse.isRedirect()) {
            Request redirectRequest = request.newBuilder().url(originalResponse.request().url()).build();
            originalResponse = chain.proceed(redirectRequest);
        }
        return originalResponse;
    }

    // func to inject params into url
    private void injectParamsIntoUrl(Request request, Request.Builder requestBuilder, Map<String, String> paramsMap) {
        HttpUrl.Builder httpUrlBuilder = request.url().newBuilder();
        if (paramsMap.size() > 0) {
            for (Map.Entry entry : paramsMap.entrySet()) {
//                httpUrlBuilder.addQueryParameter((String) entry.getKey(), (String) entry.getValue());
                httpUrlBuilder.setQueryParameter((String) entry.getKey(), (String) entry.getValue());
            }
        }
//        LzLogUtil.e("request url", httpUrlBuilder.toString());
        requestBuilder.url(httpUrlBuilder.build());
    }

    // RequestBody to String
    private String bodyToString(final RequestBody request) {
        try {
            final Buffer buffer = new Buffer();
            if (request != null)
                request.writeTo(buffer);
            else
                return "";
            return buffer.readUtf8();
        } catch (IOException e) {
            return "did not work";
        }
    }

    // MultipartBody比較特殊,把MultipartBody轉換成 k1=v1&k2=v2&kn=vn
    private String multipartBodyToString(MultipartBody body) {
        String string = "";
        try {
            Buffer buffer = new Buffer();
            body.writeTo(buffer);
            String postParams = buffer.readUtf8();
            String[] split = postParams.split("\n");

            List<String> names = new ArrayList<>();
            // Content-Disposition: form-data; name="key"
            for (String s : split) {
                if (s.contains("Content-Disposition")) {
                    String key = s.replace("Content-Disposition: form-data; name=", "")
                            .replace("\"", "")
                            .replace("\r", "")
                            .replace("\t", "");
//                    if (str.contains(";")) {
//                        key = key.substring(key.indexOf(";") + 1).trim();
//                    }
                    names.add(key.trim());
                }
            }
            List<MultipartBody.Part> parts = body.parts();
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < parts.size(); i++) {
                MultipartBody.Part part = parts.get(i);
                RequestBody body1 = part.body();
                if (body1.contentLength() < 100) {
                    Buffer buffer1 = new Buffer();
                    body1.writeTo(buffer1);
                    String value = buffer1.readUtf8();
                    //打印 name和value
                    if (names.size() > i) {
//                        LogUtil.e("aaaaaaaa", "params-->" + names.get(i) + "=" + value);
                        builder.append(names.get(i)).append("=").append(value).append("&");
                    }
                } else {
                    if (names.size() > i) {
//                        LogUtil.e("aaaaaaaa", "params-->" + names.get(i));
                        builder.append(names.get(i));
                    }
                }
            }
            string = builder.toString();
            if (string.lastIndexOf("&") == (string.length() - 1)) {
                string = string.substring(0, string.length() - 1);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return string;
    }

    private TreeMap<String, String> splitPostString(String postBodyString) {
        TreeMap<String, String> map = new TreeMap<>();
        for (String s : postBodyString.split("&")) {
            String[] keyValue = s.split("=");
            map.put(keyValue[0], keyValue.length > 1 ? keyValue[1] : "");
        }
        return map;
    }

    public void setIBasicDynamic(DynamicParams dynamicParams) {
        this.dynamicParams = dynamicParams;
    }

    public static class Builder {
        RequestInterceptor interceptor;

        /**
         * @param isJson 提交的是否是Json數據
         */
        public Builder(boolean isJson) {
            interceptor = new RequestInterceptor(isJson);
        }

        public RequestInterceptor.Builder addHeaderLine(String headerLine) {
            int index = headerLine.indexOf(":");
            if (index == -1) {
                throw new IllegalArgumentException("Unexpected header: " + headerLine);
            }
            interceptor.headerLinesList.add(headerLine);
            return this;
        }

        public RequestInterceptor.Builder addHeaderLinesList(List<String> headerLinesList) {
            for (String headerLine : headerLinesList) {
                int index = headerLine.indexOf(":");
                if (index == -1) {
                    throw new IllegalArgumentException("Unexpected header: " + headerLine);
                }
                interceptor.headerLinesList.add(headerLine);
            }
            return this;
        }

        public RequestInterceptor.Builder addHeaderParam(String key, String value) {
            interceptor.headerParamsMap.put(key, value);
            return this;
        }

        public RequestInterceptor.Builder addHeaderParamsMap(Map<String, String> headerParamsMap) {
            interceptor.headerParamsMap.putAll(headerParamsMap);
            return this;
        }

        public RequestInterceptor.Builder addUrlParam(String key, String value) {
            interceptor.urlParamsMap.put(key, value);
            return this;
        }

        public RequestInterceptor.Builder urlParamsMap(Map<String, String> urlParamsMap) {
            interceptor.urlParamsMap.putAll(urlParamsMap);
            return this;
        }

        public RequestInterceptor.Builder addBodyParam(String key, String value) {
            interceptor.bodyParamsMap.put(key, value);
            return this;
        }

        public RequestInterceptor.Builder addBodyParamsMap(Map<String, String> bodyParamsMap) {
            interceptor.bodyParamsMap.putAll(bodyParamsMap);
            return this;
        }

        public RequestInterceptor build() {
            return interceptor;
        }
    }
}

DynamicParams.java

public interface DynamicParams {
    String signParams(String postBodyString, String requestMethod, String route);
}

OkParamsInject.java

public class OkParamsInject {

    private RequestInterceptor interceptor;

    OkParamsInject() {
        // 設置靜態參數
        interceptor = new RequestInterceptor.Builder(false)
                .addBodyParam(Keys._c, "linker")
                .addBodyParam(Keys._os, Cons.os)
                .addBodyParam(Keys._v, BuildConfig.VERSION_NAME)
                .build();

        interceptor.setIBasicDynamic((postBodyString, requestMethod, route) -> {
            String s = SignUtil.getInstance().signParams(postBodyString, requestMethod, route);
            return s;
        });
    }

    Interceptor getInterceptor() {
        return interceptor;
    }
}

SignUtil.java

class SignUtil {
	// 這裏根據自己情況處理
private static SignUtil instance;

    public static SignUtil getInstance() {
        if (instance == null) {
            synchronized (SignUtil.class) {
                if (instance == null) {
                    instance = new SignUtil();
                }
            }
        }
        return instance;
    }

    public String signParams(String postBodyString, String requestMethod, String route) {
        TreeMap<String, String> treeMap = splitPostString(postBodyString);
        treeMap = dynamicParams(treeMap);
        String sign;
        // post請求參數在RequestBody中,被encode了,get請求參數在FormBody中,沒有被encode,這裏要區分處理。
        if ("GET".equals(requestMethod)) {
            sign = getSignNoDecode(treeMap, route);
        } else {
            sign = getSign(treeMap, route);
        }
        treeMap.put(Keys._s, sign);
        return getPostParamsStr(treeMap);
    }

    /**
     * 分割請求參數,放入treeMap中,拼接動態參數
     *
     * @param postBodyString 請求參數
     */
    private TreeMap<String, String> splitPostString(String postBodyString) {
        TreeMap<String, String> map = new TreeMap<>();
        for (String s : postBodyString.split("&")) {
            String[] keyValue = s.split("=");
            map.put(keyValue[0], keyValue.length > 1 ? keyValue[1] : "");
        }
        return map;
    }

    public TreeMap<String, String> dynamicParams(TreeMap<String, String> map) {
        String token = MyApp.getInstance().getUserInfo().token;
        String userId = MyApp.getInstance().getUserInfo().id;
        String userOnly = MyApp.getInstance().getUserInfo().i;
        String deviceId = DeviceUtils.getUUID();
        map.put(Keys._ts, String.valueOf(System.currentTimeMillis() / 1000));
        map.put(Keys._r, StringUtils.get_r(6));
        if (!TextUtils.isEmpty(deviceId)) {
            map.put(Keys._idfa, deviceId);
        }
        if (!TextUtils.isEmpty(userOnly)) {
            map.put(Keys._i, userOnly);
        }
        if (!TextUtils.isEmpty(token)) {
            map.put(Keys._t, token);
        }
        if (!TextUtils.isEmpty(userId)) {
            map.put(Keys._u, userId);
        }
        return map;
    }

    /**
     * 一般接口調用-signa簽名生成規則
     *
     * @param map 有序請求參數map
     */
    public static String getSign(TreeMap map, String route) {
        String signa = "";
        Iterator it = map.entrySet().iterator();
        StringBuilder sb = new StringBuilder();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            if (null != entry.getValue()) {
                try {
                    sb.append(entry.getKey()).append("=").append(URLDecoder.decode(entry.getValue().toString(), "utf-8")).append("&");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
            }
        }
        // 所有請求參數排序後的字符串後進行MD5(32)
        // 路由地址+參數排序+app_secret
        String str = route + Cons.os + sb.deleteCharAt(sb.length() - 1).toString() + sign_key;
        String str1 = str.toLowerCase();
        LogUtil.e("SignUtil", "sign_string:" + str1);
        signa = MD5Util.getMD5String(str1).toLowerCase();
        LogUtil.e("SignUtil", "sign:" + signa);
        return signa;
    }

    /**
     * 一般接口調用-signa簽名生成規則
     *
     * @param map   有序請求參數map
     * @param route
     */
    public static String getSignNoDecode(TreeMap map, String route) {
        String signa = "";
        Iterator it = map.entrySet().iterator();
        StringBuilder sb = new StringBuilder();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            if (null != entry.getValue()) {
                // 之前沒有encode過,這裏如果decode可能會出問題,例如+號在沒有encode過的情況下去decode會變成空格
                sb.append(entry.getKey()).append("=").append(entry.getValue().toString()).append("&");
            }
        }
        // 所有請求參數排序後的字符串後進行MD5(32)
        String str = route + Cons.os + sb.deleteCharAt(sb.length() - 1).toString() + sign_key;
        String str1 = str.toLowerCase();
//        LogUtil.e("before sign1 ======", str1);
        signa = MD5Util.getMD5String(str1).toLowerCase();
//        LogUtil.e("sign1 ==========", signa);
        return signa;
    }

    /**
     * 將map拼裝成請求字符串
     *
     * @return 返回請求參數
     */
    private String getPostParamsStr(TreeMap map) {
        Iterator it = map.entrySet().iterator();
        StringBuilder sb = new StringBuilder();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            if (null != entry.getValue()) {
                sb.append(entry.getKey()).append("=").append(entry.getValue().toString()).append("&");
            }
        }
        String sb1;
        if (sb.toString().length() > 1) {
            sb1 = sb.toString().substring(0, sb.length() - 1);
        } else {
            sb1 = sb.toString();
        }
        LogUtil.e("SignUtil", "after_sign:" + sb1);
        return sb1;
    }
}

請求調用的類
OkClient.java

public class OkClient {

    private static OkClient INSTANCE;
    private static long time_out = 5 * 1000;

    private OkHttpClient okHttpClient;
    private Handler mHandler;
    private final HashMap<String, List<Cookie>> cookieMap = new HashMap<>();
    private ResponseInterceptor responseInterceptor = new ResponseInterceptor();

    private OkClient() {
        okHttpClient = new OkHttpClient.Builder()
                .cookieJar(new CookieJar() {
                    @Override
                    public void saveFromResponse(@NotNull HttpUrl httpUrl, @NotNull List<Cookie> list) {
                        cookieMap.put(httpUrl.host(), list);
                    }

                    @NotNull
                    @Override
                    public List<Cookie> loadForRequest(@NotNull HttpUrl httpUrl) {
                        List<Cookie> cookies = cookieMap.get(httpUrl.host());
                        return cookies != null ? cookies : new ArrayList<>();
                    }
                })
                .addInterceptor(new OkParamsInject().getInterceptor())
                .addInterceptor(responseInterceptor)
                .retryOnConnectionFailure(true)
                .connectTimeout(time_out, TimeUnit.SECONDS)
                .writeTimeout(time_out, TimeUnit.SECONDS)
                .readTimeout(time_out, TimeUnit.SECONDS)
                .build();
        mHandler = new Handler(Looper.getMainLooper());
    }

    public static OkClient getInstance() {
        if (INSTANCE == null) {
            synchronized (OkClient.class) {
                if (INSTANCE == null) {
                    INSTANCE = new OkClient();
                }
            }
        }
        return INSTANCE;
    }

    //==============================================================================================
	// GET請求
    public void getAsyn(Context context, String url, ResultCallback<String> callback) {
        _getAsyn(context, "域名" + url, callback);
    }

	// POST請求
    public void postAsyn(Context context, String url, Map<String, String> params, ResultCallback<String> callback) {
        _postAsyn(context, "域名" + url, params, callback);
    }

	// POST上傳文件
    public void postImg(Context context, String url, String key, File file, Map<String, String> params, ResultCallback<String> callback) {
        _postImg(context, "域名" + url, file, key, params, callback);
    }

    //==============================================================================================

    /**
     * get異步請求
     *
     * @param url
     * @param callback
     */
    private void _getAsyn(Context context, String url, ResultCallback<String> callback) {
//        LogUtil.e("OkClient", "get_url:" + url);
        Request request = new Request.Builder()
                .url(url)
                .build();
        deliveryResult(context, callback, request);
    }

    /**
     * post異步請求
     *
     * @param url
     * @param params
     * @param callback
     */
    private void _postAsyn(Context context, String url, Map<String, String> params, ResultCallback<String> callback) {
        Param[] params1 = map2Params(params);
        Request request = buildPostRequest(url, params1);
        deliveryResult(context, callback, request);
    }

    /**
     * post上傳圖片
     *
     * @param url
     * @param file
     * @param fileKey
     * @param params
     * @param callback
     */
    private void _postImg(Context context, String url, File file, String fileKey, Map<String, String> params, ResultCallback<String> callback) {
        Request request = buildMultipartFormRequest(url, file, fileKey, params);
        deliveryResult(context, callback, request);
    }

    private Param[] map2Params(Map<String, String> params) {
        if (params == null) return new Param[0];
        int size = params.size();
        Param[] res = new Param[size];
        Set<Map.Entry<String, String>> entries = params.entrySet();
        int i = 0;
        for (Map.Entry<String, String> entry : entries) {
            res[i++] = new Param(entry.getKey(), entry.getValue());
        }
        return res;
    }

    /**
     * 請求回調處理方法並傳遞返回值
     *
     * @param callback Map類型請求參數
     * @param request  Request請求
     */
    private void deliveryResult(Context context, ResultCallback<String> callback, Request request) {
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                sendFailedStringCallback(e, callback);
            }

            @Override
            public void onResponse(Call call, Response response) {

            }

        });
        /** 
         * 此處可以在上面的回調中處理,之所以使用響應攔截器來處理,是因爲我在某種情況多次調用同一個接口時,後面的請求沒有響應。
        */
        responseInterceptor.setCallback(new ResInterceptorCallback() {
            @Override
            public void onResponse(String jsonResult) {
                sendSuccessResultCallback(context, jsonResult, callback);
            }
        });
    }

    /**
     * 處理請求失敗的回調信息方法
     *
     * @param e        錯誤信息
     * @param callback 回調類
     */
    private void sendFailedStringCallback(Exception e, ResultCallback callback) {
        mHandler.post(() -> {
            if (callback != null)
                callback.onError(0, e.getMessage());
        });
    }

    /**
     * 處理請求成功的回調信息方法
     *
     * @param json 服務器響應信息
     */
    private void sendSuccessResultCallback(Context context, String json, ResultCallback callback) {
        mHandler.post(() -> {
            int code;
            String msg;
            String data;
            try {
                JSONObject jsonObject = new JSONObject(json);
                code = jsonObject.optInt("code");
                data = jsonObject.optString("data");
                msg = jsonObject.optString("info");

                if (code == 200) {
                    if (callback != null) callback.onResponse(data, msg, code);
                } else {
                    errorCode(context, code, msg);
                    if (callback != null) callback.onError(code, msg);
                }
            } catch (JSONException e) {
                e.printStackTrace();
                if (callback != null) callback.onError(0, "數據解析出現錯誤");
            }
        });
    }

    private void errorCode(Context context, int code, String msg) {
        LogUtil.e("OkClient", "request_error code:" + code + ", msg:" + msg);
        switch (code) {
            case 0:// 驗證失敗

                break;
            case 401:// 登錄信息失效
                LoginUtil.clearUserInfo();
                DialogUtil.showJustDetermineDialog(context, "登錄信息失效,請重新登錄!", v -> OpenUtil.startActivity(context, LoginActivity.class));
                break;
            case 404:// 訪問路徑不存在

                break;
            case 405:// 訪問方法不被允許

                break;
            case 406:// 請求中存在敏感詞

                break;
        }
    }

    /**
     * 創建 PostRequest
     *
     * @param url    url
     * @param params params
     * @return request
     */
    private Request buildPostRequest(String url, Param[] params) {
        if (params == null) {
            params = new Param[0];
        }
        FormBody.Builder builder = new FormBody.Builder();
        for (Param param : params) {
            builder.add(param.key, param.value);
        }
        RequestBody requestBody = builder.build();
        return new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();
    }

    private Request buildMultipartFormRequest(String url, File file, String key, Map<String, String> params) {
        if (params == null) params = new HashMap<>();
        MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
        for (Map.Entry entry : params.entrySet()) {
            builder.addFormDataPart((String) entry.getKey(), (String) entry.getValue());
        }
        builder.addFormDataPart(key, file.getName(), RequestBody.create(MediaType.parse("image/*"), file));
        RequestBody requestBody = builder.build();
        return new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();
    }

    public static class Param {
        public Param() {
        }

        public Param(String key, String value) {
            this.key = key;
            this.value = value;
        }

        String key;
        String value;
    }
}

響應攔截器:
ResponseInterceptor.java

public class ResponseInterceptor implements Interceptor {

    private static final Charset UTF8 = Charset.forName("UTF-8");

    private ResInterceptorCallback callback;

    public void setCallback(ResInterceptorCallback callback) {
        this.callback = callback;
    }

    @Override
    public Response intercept(Chain chain) throws IOException {

        Request request = chain.request();
        Response response = chain.proceed(request);

        ResponseBody responseBody = response.body();
        long contentLength = responseBody.contentLength();

        //注意 >>>>>>>>> okhttp3.4.1這裏變成了 !HttpHeader.hasBody(response)
        //if (!HttpEngine.hasBody(response)) {
        if(!HttpHeaders.hasBody(response)){ //HttpHeader -> 改成了 HttpHeaders,看版本進行選擇
            //END HTTP
        } else if (bodyEncoded(response.headers())) {
            //HTTP (encoded body omitted)
        } else {
            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) {
                try {
                    charset = contentType.charset(UTF8);
                } catch (UnsupportedCharsetException e) {
                    //Couldn't decode the response body; charset is likely malformed.
                    return response;
                }
            }

            if (!isPlaintext(buffer)) {
                return response;
            }

            if (contentLength != 0) {
                String result = buffer.clone().readString(charset);

                /**
                 * 由於Response.body.string()後,後面的操作就直接返回Failed了,估計是因爲流只能被使用一次的原因
                 * 有時候請求沒有相應,根據OkHttp的日誌攔截器的思想處理此問題。
                 * 獲取到response的body的string字符串
                 */
                //do something .... <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
//                LogUtil.e("ResponseInterceptor", "result:" + result);
                if (callback != null) callback.onResponse(result);
            }

        }
        return response;
    }

    static boolean isPlaintext(Buffer buffer) {
        try {
            Buffer prefix = new Buffer();
            long byteCount = buffer.size() < 64 ? buffer.size() : 64;
            buffer.copyTo(prefix, 0, byteCount);
            for (int i = 0; i < 16; i++) {
                if (prefix.exhausted()) {
                    break;
                }
                int codePoint = prefix.readUtf8CodePoint();
                if (Character.isISOControl(codePoint) && !Character.isWhitespace(codePoint)) {
                    return false;
                }
            }
            return true;
        } catch (EOFException e) {
            return false; // Truncated UTF-8 sequence.
        }
    }

    private boolean bodyEncoded(Headers headers) {
        String contentEncoding = headers.get("Content-Encoding");
        return contentEncoding != null && !contentEncoding.equalsIgnoreCase("identity");
    }
}

使用:

public static void addAds(Context context, String adIds, String stream_name, ResultCallback<String> callback) {
        Map<String, String> params = new HashMap<>();
        params.put("ad_ids", String.valueOf(adIds));
        params.put("stream_name", stream_name);
        OkClient.getInstance().postAsyn(context, "請求路由(不包含域名)", params, callback);
    }

主要提供了GET、POST請求和POST上傳文件3中方法,使用OkHttp3下載文件見下一篇文章,關於上傳進度也可以參照下載。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章