记OkHttpClient 踩的坑

该博客介绍了由于OkHttpClient未使用单例导致的端口耗尽和内存溢出问题。通过修改代码,将OkHttpClient实例化为单例,解决了资源浪费和性能瓶颈。文中提供了解决方案的详细步骤,并展示了修改前后的代码对比。

某次运营搞活动,端口耗尽,内存溢出,查代码,原来是OkHttpClient没有单列导致。

原代码:

pom

<dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>4.2.1</version>
        </dependency>

import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

@Slf4j
public class HttpClient {

    public static final String  REQUESTBODY_MEDIATYPE="application/json; charset=utf-8";
    public static final String  REQUESTPARAM_MEDIATYPE="application/x-www-form-urlencoded; charset=utf-8";
    public static final String  REQUESTBODYXML_MEDIATYPE="application/xml; charset=utf-8";
    public static final Integer  DEFUAL_TIME_OUT= 5;

    /**
     * post默认使用RequestParam
     * @param url
     * @param json 请求参数sign=0b7a15733db14d402329cbcefeecca45&timestamp=1571275708
     * @return
     */
    public static Optional<String> doPost(String url, String json) {
        return doPost(url, json,REQUESTPARAM_MEDIATYPE,null, DEFUAL_TIME_OUT);
    }

    /**
     * post默认使用RequestParam
     * @param url
     * @param json 请求参数sign=0b7a15733db14d402329cbcefeecca45&timestamp=1571275708
     * @param timeout 超时时间s
     * @return
     */
    public static Optional<String> doPost(String url, String json, Integer timeout) {
        return doPost(url, json,REQUESTPARAM_MEDIATYPE,null, timeout);
    }

    /**
     * post默认使用RequestParam
     * @param url
     * @param json 请求参数sign=0b7a15733db14d402329cbcefeecca45&timestamp=1571275708
     * @param headersParams header参数map
     * @return
     */
    public static Optional<String> doPost(String url, String json,Map<String, Object> headersParams) {
        return doPost(url, json,REQUESTPARAM_MEDIATYPE,headersParams, DEFUAL_TIME_OUT);
    }

    /**
     * doPost
     * @param url
     * @param json requestType=REQUESTPARAM_MEDIATYPE时,传入actId=104&sign=0b7a15733db14d402329cbcefeecca45&timestamp=1571275708
     *             requestType=REQUESTBODY_MEDIATYPE时,传入{"actCode":"JIQnAnbDrkyXzJbvUnfS","accessid":"9001","sign":"433954b00d03ef14a19455859517267c","timestamp":"1571275779"}
     * @param requestType RequestBody则传入 REQUESTBODY_MEDIATYPE;RequestParam则传入REQUESTPARAM_MEDIATYPE
     * @return
     */
    public static Optional<String> doPost(String url, String json,String requestType){
        return doPost(url, json,requestType,null, DEFUAL_TIME_OUT);
    }

    public static Optional<String> doPost(String url, String json,String requestType,Map<String, Object> headersParams){
        return doPost(url, json,requestType,headersParams, DEFUAL_TIME_OUT);
    }

    /**
     * doPost
     * @param url
     * @param json REQUESTPARAM_MEDIATYPE时,传入actId=104&sign=0b7a15733db14d402329cbcefeecca45&timestamp=1571275708
     *             REQUESTBODY_MEDIATYPE时,传入{"actCode":"JIQnAnbDrkyXzJbvUnfS","accessid":"9001","sign":"433954b00d03ef14a19455859517267c","timestamp":"1571275779"}
     * @param requestType RequestBody则传入 REQUESTBODY_MEDIATYPE;RequestParam则传入REQUESTPARAM_MEDIATYPE
     * @param headersParams
     * @return
     */
    public static Optional<String> doPost(String url, String json,String requestType,Map<String, Object> headersParams, Integer timeout) {
        MediaType mediaType=MediaType.parse(requestType);
        OkHttpClient httpClient = new OkHttpClient().newBuilder().connectTimeout(timeout, TimeUnit.SECONDS).readTimeout(timeout, TimeUnit.SECONDS).build();
        RequestBody body = RequestBody.create(mediaType,json);
        Request request = new Request.Builder()
                .url(url)
                .post(body).headers(setHeaders(headersParams))
                .build();
        try (Response response = httpClient.newCall(request).execute()) {
            return Optional.of(response.body().string());
        } catch (Exception e) {
            log.error("post 请求 【" + url + "] 异常, 入参 [" + json + "]", e);
        }
        return Optional.empty();
    }


    public static Optional<String> doPostXml(String url, String xmlString) {
        RequestBody body=RequestBody.create(MediaType.parse(REQUESTBODYXML_MEDIATYPE), xmlString);
        OkHttpClient httpClient = new OkHttpClient().newBuilder().connectTimeout(10, TimeUnit.SECONDS).readTimeout(10, TimeUnit.SECONDS).build();
        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .build();
        try (Response response = httpClient.newCall(request).execute()) {
            return Optional.of(response.body().string());
        } catch (Exception e) {
            log.error("post 请求 【" + url + "] 异常, 入参 [" + xmlString + "]", e);
        }
        return Optional.empty();
    }

    /**
     * 设置Header头
     * @param headersParams
     * @return
     */
    private static Headers setHeaders(Map<String,Object> headersParams){
        Headers headers = null;
        Headers.Builder headerBuilder = new Headers.Builder();
        if(headersParams != null){
            for (String key:headersParams.keySet()){
                headerBuilder.add(key,headersParams.get(key).toString());
            }
        }
        headers = headerBuilder.build();

        return headers;
    }

    /**
     * get请求
     * @param url
     * @return
     */
    public static Optional<String> get(String url) {
        OkHttpClient httpClient = new OkHttpClient().newBuilder().connectTimeout(DEFUAL_TIME_OUT, TimeUnit.SECONDS).readTimeout(DEFUAL_TIME_OUT, TimeUnit.SECONDS).build();

        Request request = new Request.Builder().url(url).build();
        try (Response response = httpClient.newCall(request).execute()) {
            return Optional.of(response.body().string());
        } catch (Exception e) {
            log.error("get 请求 【" + url + "] 异常", e);
        }
        return Optional.empty();
    }


    public static String getQueryString(Map<String, String> params) {
        if (params == null) {
            return null;
        } else {
            String q = "";
            int i = 0;
            Iterator var3 = params.entrySet().iterator();

            while(var3.hasNext()) {
                Map.Entry param = (Map.Entry)var3.next();

                try {
                    q = q + param.getKey() + "=" + URLEncoder.encode(param.getValue()==null?"":param.getValue().toString(), "utf-8");
                } catch (UnsupportedEncodingException var6) {
                    ;
                }

                ++i;
                if (i != params.size()) {
                    q = q + "&";
                }
            }

            return q;
        }
    }

    public static String getQueryObject(Map<String, Object> params) {
        if (params == null) {
            return null;
        } else {
            String q = "";
            int i = 0;
            Iterator var3 = params.entrySet().iterator();

            while(var3.hasNext()) {
                Map.Entry param = (Map.Entry)var3.next();

                try {

                    if (param.getValue() instanceof Collection) {
                        for (Object s : (Collection)param.getValue()) {
                            q = q + param.getKey() + "=" + URLEncoder.encode(param.getValue()==null?"":s.toString(), "utf-8");
                        }
                    } else {
                        q = q + param.getKey() + "=" + URLEncoder.encode(param.getValue()==null?"":param.getValue().toString(), "utf-8");
                    }
                } catch (UnsupportedEncodingException var6) {
                    ;
                }
                ++i;
                if (i != params.size()) {
                    q = q + "&";
                }
            }

            return q;
        }
    }
}

修改后:


import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;


@Slf4j
public class HttpClient {

    public static final String  REQUESTBODY_MEDIATYPE="application/json; charset=utf-8";
    public static final String  REQUESTPARAM_MEDIATYPE="application/x-www-form-urlencoded; charset=utf-8";
    public static final String  REQUESTBODYXML_MEDIATYPE="application/xml; charset=utf-8";
    public static final Integer  DEFUAL_TIME_OUT= 5;

    /**
     * post默认使用RequestParam
     * @param url
     * @param json 请求参数sign=0b7a15733db14d402329cbcefeecca45&timestamp=1571275708
     * @return
     */
    public static Optional<String> doPost(String url, String json) {
        return doPost(url, json,REQUESTPARAM_MEDIATYPE,null, DEFUAL_TIME_OUT);
    }

    /**
     * post默认使用RequestParam
     * @param url
     * @param json 请求参数sign=0b7a15733db14d402329cbcefeecca45&timestamp=1571275708
     * @param timeout 超时时间s
     * @return
     */
    public static Optional<String> doPost(String url, String json, Integer timeout) {
        return doPost(url, json,REQUESTPARAM_MEDIATYPE,null, timeout);
    }

    /**
     * post默认使用RequestParam
     * @param url
     * @param json 请求参数sign=0b7a15733db14d402329cbcefeecca45&timestamp=1571275708
     * @param headersParams header参数map
     * @return
     */
    public static Optional<String> doPost(String url, String json,Map<String, Object> headersParams) {
        return doPost(url, json,REQUESTPARAM_MEDIATYPE,headersParams, DEFUAL_TIME_OUT);
    }

    /**
     * doPost
     * @param url
     * @param json requestType=REQUESTPARAM_MEDIATYPE时,传入actId=104&sign=0b7a15733db14d402329cbcefeecca45&timestamp=1571275708
     *             requestType=REQUESTBODY_MEDIATYPE时,传入{"actCode":"JIQnAnbDrkyXzJbvUnfS","accessid":"9001","sign":"433954b00d03ef14a19455859517267c","timestamp":"1571275779"}
     * @param requestType RequestBody则传入 REQUESTBODY_MEDIATYPE;RequestParam则传入REQUESTPARAM_MEDIATYPE
     * @return
     */
    public static Optional<String> doPost(String url, String json,String requestType){
        return doPost(url, json,requestType,null, DEFUAL_TIME_OUT);
    }

    public static Optional<String> doPost(String url, String json,String requestType,Map<String, Object> headersParams){
        return doPost(url, json,requestType,headersParams, DEFUAL_TIME_OUT);
    }

    /**
     * doPost
     * @param url
     * @param json REQUESTPARAM_MEDIATYPE时,传入actId=104&sign=0b7a15733db14d402329cbcefeecca45&timestamp=1571275708
     *             REQUESTBODY_MEDIATYPE时,传入{"actCode":"JIQnAnbDrkyXzJbvUnfS","accessid":"9001","sign":"433954b00d03ef14a19455859517267c","timestamp":"1571275779"}
     * @param requestType RequestBody则传入 REQUESTBODY_MEDIATYPE;RequestParam则传入REQUESTPARAM_MEDIATYPE
     * @param headersParams
     * @return
     */
    public static Optional<String> doPost(String url, String json,String requestType,Map<String, Object> headersParams, Integer timeout) {
        MediaType mediaType=MediaType.parse(requestType);
        RequestBody body = RequestBody.create(mediaType,json);
        Request request = new Request.Builder()
                .url(url)
                .post(body).headers(setHeaders(headersParams))
                .build();
        try (Response response = OkHttpUtil.getInstance().newCall(request).execute()) {
            return Optional.of(response.body().string());
        } catch (Exception e) {
            log.error("post 请求 【" + url + "] 异常, 入参 [" + json + "]", e);
        }
        return Optional.empty();
    }


    public static Optional<String> doPostXml(String url, String xmlString) {
        RequestBody body=RequestBody.create(MediaType.parse(REQUESTBODYXML_MEDIATYPE), xmlString);
        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .build();
        try (Response response = OkHttpUtil.getInstance().newCall(request).execute()) {
            return Optional.of(response.body().string());
        } catch (Exception e) {
            log.error("post 请求 【" + url + "] 异常, 入参 [" + xmlString + "]", e);
        }
        return Optional.empty();
    }

    /**
     * 设置Header头
     * @param headersParams
     * @return
     */
    private static Headers setHeaders(Map<String,Object> headersParams){
        Headers headers = null;
        Headers.Builder headerBuilder = new Headers.Builder();
        if(headersParams != null){
            for (String key:headersParams.keySet()){
                headerBuilder.add(key,headersParams.get(key).toString());
            }
        }
        headers = headerBuilder.build();

        return headers;
    }

    /**
     * get请求
     * @param url
     * @return
     */
    public static Optional<String> get(String url) {
        Request request = new Request.Builder().url(url).build();
        try (Response response = OkHttpUtil.getInstance().newCall(request).execute()) {
            return Optional.of(response.body().string());
        } catch (Exception e) {
            log.error("get 请求 【" + url + "] 异常", e);
        }
        return Optional.empty();
    }


    public static String getQueryString(Map<String, String> params) {
        if (params == null) {
            return null;
        } else {
            String q = "";
            int i = 0;
            Iterator var3 = params.entrySet().iterator();

            while(var3.hasNext()) {
                Map.Entry param = (Map.Entry)var3.next();

                try {
                    q = q + param.getKey() + "=" + URLEncoder.encode(param.getValue()==null?"":param.getValue().toString(), "utf-8");
                } catch (UnsupportedEncodingException var6) {
                    ;
                }

                ++i;
                if (i != params.size()) {
                    q = q + "&";
                }
            }

            return q;
        }
    }

    public static String getQueryObject(Map<String, Object> params) {
        if (params == null) {
            return null;
        } else {
            String q = "";
            int i = 0;
            Iterator var3 = params.entrySet().iterator();

            while(var3.hasNext()) {
                Map.Entry param = (Map.Entry)var3.next();

                try {

                    if (param.getValue() instanceof Collection) {
                        for (Object s : (Collection)param.getValue()) {
                            q = q + param.getKey() + "=" + URLEncoder.encode(param.getValue()==null?"":s.toString(), "utf-8");
                        }
                    } else {
                        q = q + param.getKey() + "=" + URLEncoder.encode(param.getValue()==null?"":param.getValue().toString(), "utf-8");
                    }
                } catch (UnsupportedEncodingException var6) {
                    ;
                }
                ++i;
                if (i != params.size()) {
                    q = q + "&";
                }
            }

            return q;
        }
    }
}

单列化:


import okhttp3.OkHttpClient;

import java.util.concurrent.TimeUnit;


public class OkHttpUtil {

    private static volatile OkHttpClient singleton;
    public static final Integer  DEFAULT_TIME_OUT= 7;

    private OkHttpUtil() {

    }


    public static OkHttpClient getInstance() {
        if (singleton == null) {
            synchronized (OkHttpUtil.class) {
                if (singleton == null) {
                    singleton = new OkHttpClient()
                            .newBuilder()
                            .connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS)
                            .readTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS)
                            .writeTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS)
                            .build();
                }
            }
        }
        return singleton;
    }

}

参考地址:OkHttp使用踩坑记录总结(一):OkHttpClient单例和长连接Connection Keep-Alive_wds的博客-CSDN博客_okhttpclient 单例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值