跳至主要內容

HttpUtil

程序员李某某大约 7 分钟

HttpUtil

依赖

 <dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.13</version>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpmime</artifactId>
    <version>4.5.13</version>
</dependency>

工具类

package com.jd.starlink.util;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.ConnectionConfig;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * HttpClientUtil
 * http请求工具类
 *
 * @author sunbin
 * @date 2019/7/9
 */
@Slf4j
public class HttpClientUtil {
    /**
     * httpClient
     */
    private static final HttpClient HTTP_CLIENT;

    /**
     * 默认连接超时时间
     */
    private static final int DEFAULT_CONN_TIME_OUT = 15000;
    /**
     * 默认socket超时时间
     */
    private static final int DEFAULT_SOCKET_TIME_OUT = 30000;
    /**
     * 默认请求超时时间
     */
    private static final int DEFAULT_REQ_TIME_OUT = 15000;
    
    public enum HttpMethodEnum {
        GET, POST, DELETE, HEAD, OPTIONS, PUT, TRACE;
    }
    static {
        ConnectionConfig connectionConfig = ConnectionConfig.custom().setCharset(StandardCharsets.UTF_8).build();
        HttpClientBuilder builder = HttpClientBuilder.create();
        builder.setConnectionTimeToLive(30 * 1000, TimeUnit.MILLISECONDS);
        builder.setDefaultConnectionConfig(connectionConfig);
        builder.setMaxConnPerRoute(1000);
        builder.setMaxConnTotal(1000);
        HTTP_CLIENT = builder.build();
    }

    /**
     * Description 发送post请求
     *
     * @author ZhangChaoFu(zhangchaofu @ jd.com)
     * Date 2019/3/14 10:27
     */
    private static String doPost(HttpPost httpPost) {
        try {
            HttpResponse response = HTTP_CLIENT.execute(httpPost);
//            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(15 * 1000)
//                    .setSocketTimeout(30 * 1000).setConnectionRequestTimeout(15 * 1000).build();
//            httpPost.setConfig(requestConfig);

            HttpEntity httpEntity = response.getEntity();
            if (httpEntity == null) {
                log.error("HttpClientUtil.doPost--httpEntity--null");
                return null;
            }
            String responseString = EntityUtils.toString(httpEntity, StandardCharsets.UTF_8);
            EntityUtils.consume(httpEntity);
            return responseString;
        } catch (Exception e) {
            log.error("HttpClientUtil.doPost--exception", e);
            return null;
        }

    }

    /**
     * Description http post请求
     *
     * @param entity 请求实体
     * @return java.lang.String
     * @author ZhangChaoFu(zhangchaofu @ jd.com)
     * @date 2019-11-06
     */
    public static String doPost(RequestEntity entity) {
        HttpPost post = null;
        try {
            if (entity == null) {
                return null;
            }
            if (StringUtils.isBlank(entity.getUrl())) {
                return null;
            }
            post = new HttpPost(entity.getUrl());
            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(entity.getConnectionTimeout())
                    .setSocketTimeout(entity.getSocketTimeout())
                    .setConnectionRequestTimeout(entity.getConnectionRequestTimeout()).build();
            post.setConfig(requestConfig);
            if (entity.getParams() != null && !entity.getParams().isEmpty()) {
                List<NameValuePair> list = new ArrayList<>(entity.getParams().size());
                entity.getParams().forEach((key, value) ->
                        list.add(new BasicNameValuePair(key, value))
                );
                post.setEntity(new UrlEncodedFormEntity(list, StandardCharsets.UTF_8));
            }
            if (entity.getHeader() != null && !entity.getHeader().isEmpty()) {
                for (Map.Entry<String, String> en : entity.getHeader().entrySet()) {
                    post.addHeader(en.getKey(), en.getValue());
                }
            }

            return doPost(post);
        } catch (Exception e) {
            log.error("HttpClientUtil.doPost--exception", e);
            return null;
        } finally {
            if (post != null) {
                post.releaseConnection();
            }
        }
    }

    /**
     * Description http post请求
     *
     * @param url    请求地址
     * @param params 请求参数
     * @return java.lang.String
     * @author ZhangChaoFu(zhangchaofu @ jd.com)
     * @date 2019-11-06
     */
    public static String doPost(String url, Map<String, String> params, Map<String, String> header) {
        RequestEntity entity = new RequestEntity();
        entity.setUrl(url);
        entity.setParams(params);
        entity.setHeader(header);
        entity.setConnectionTimeout(DEFAULT_CONN_TIME_OUT);
        entity.setSocketTimeout(DEFAULT_SOCKET_TIME_OUT);
        entity.setConnectionRequestTimeout(DEFAULT_REQ_TIME_OUT);
        return doPost(entity);
    }

    /**
     * 上传文件流 add by yezhenyue
     * @param  name 文件接收server端指定的参数名比如 file
      * @param inputStream 文件流
     * @param fileName 文件名
     * @param url server地址
     * @param params 附加key-value参数
     * @return
     */
    public static String postInputStream(String name,InputStream inputStream,String fileName, String url, Map<String, String> params, Map<String, String> headers) {
        HttpPost httpPost = new HttpPost(url);
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(5 * 1000)//链接超时时间
                .setSocketTimeout(120 * 1000)//socket读超时时间,文件上传需要设置长一点
                .setConnectionRequestTimeout(5 * 1000).build();//从链接池获取链接超时时间
        httpPost.setConfig(requestConfig);
        if (headers!=null){
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                httpPost.addHeader(entry.getKey(),entry.getValue());
            }
        }
        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
        builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
        builder.setCharset(StandardCharsets.UTF_8);
        builder.addBinaryBody(name, inputStream, ContentType.MULTIPART_FORM_DATA, fileName);
        if (params != null) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                builder.addTextBody(entry.getKey(), entry.getValue());
            }
        }

        httpPost.setEntity(builder.build());
        return doPost(httpPost);
    }
    /**
     * Description 已输入流的方式(InputStream)发送文件和其他参数
     *
     * @author ZhangChaoFu(zhangchaofu @ jd.com)
     * Date 2019/3/14 10:27
     */
    public static String postUploadFileByInputStream(InputStream is, String fileName, String url, Map<String, String> params) {
        Map<String, byte[]> images = null;
        try {
            if (is != null) {
                byte[] buffer = new byte[1024];
                int i;
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                while ((i = is.read(buffer, 0, buffer.length)) != -1) {
                    bos.write(buffer, 0, i);
                }
                byte[] bytes = bos.toByteArray();
                images = new HashMap<>(params.size() + 2);
                images.put(fileName, bytes);
            }

            return postUploadFileByByte(images, url, params);
        } catch (Exception e) {
            log.error("HttpClientUtil.postUploadFileByInputStream--exception", e);
            return null;
        }
    }

    /**
     * Description 字节流方式上传文件
     *
     * @author ZhangChaoFu(zhangchaofu @ jd.com)
     * Date 2019/3/21 11:24
     */
    public static String postUploadFileByByte(Map<String, byte[]> images, String url, Map<String, String> params) {
        try {
            HttpPost httpPost = new HttpPost(url);
            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(5 * 1000)
                    .setSocketTimeout(5 * 1000).setConnectionRequestTimeout(5 * 1000).build();
            httpPost.setConfig(requestConfig);

            MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
            //这个mode参数设置很重要否则调不通算法新接口
            multipartEntityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);

            if (images != null) {
                for (Map.Entry<String, byte[]> entry : images.entrySet()) {
                    multipartEntityBuilder.addBinaryBody(entry.getKey(), entry.getValue(),
                            ContentType.MULTIPART_FORM_DATA, entry.getKey());
                }
            }

            if (params != null) {
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    multipartEntityBuilder.addTextBody(entry.getKey(), entry.getValue());
                }
            }

            httpPost.setEntity(multipartEntityBuilder.build());
            return doPost(httpPost);
        } catch (Exception e) {
            log.error("HttpClientUtil.postUploadFileByByte--exception", e);
            return null;
        }
    }

    /**
     * 以application/octet-stream类型上传图片
     *
     * @param images 图片
     * @param url    上传地址
     * @param params 其他参数
     * @return java.lang.String
     */
    public static String postUploadFileByByteAndOctet(Map<String, byte[]> images, String url, Map<String, String> params) {
        try {
            HttpPost httpPost = new HttpPost(url);
            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(5 * 1000)
                    .setSocketTimeout(5 * 1000).setConnectionRequestTimeout(5 * 1000).build();
            httpPost.setConfig(requestConfig);

            MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();

            multipartEntityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
            if (images != null) {
                for (Map.Entry<String, byte[]> entry : images.entrySet()) {
                    multipartEntityBuilder.addBinaryBody(entry.getKey(), entry.getValue(),
                            ContentType.APPLICATION_OCTET_STREAM, entry.getKey());
                }
            }

            if (params != null) {
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    multipartEntityBuilder.addTextBody(entry.getKey(), entry.getValue());
                }
            }

            httpPost.setEntity(multipartEntityBuilder.build());
            return doPost(httpPost);
        } catch (Exception e) {
            log.error("HttpClientUtil.postUploadFileByByte--exception", e);
            return null;
        }
    }

    /**
     * json参数方式POST提交
     *
     * @param url
     * @param jsonString
     * @return
     */
    public static String doPost(String url, String jsonString) {
        String strResult = "";
        HttpPost httpPost = new HttpPost(url);
        httpPost.addHeader("Content-Type", "application/json;charset=utf-8"); //添加请求头
        try {
            httpPost.setEntity(new StringEntity(jsonString, "utf-8"));
            HttpResponse resp = HTTP_CLIENT.execute(httpPost);
            HttpEntity respEntity = resp.getEntity();
            strResult = EntityUtils.toString(respEntity, "UTF-8");
            int statusCode = resp.getStatusLine().getStatusCode();
            if (statusCode != HttpsURLConnection.HTTP_OK){
                log.error("http post error url:{},params:{},result:{}",url,jsonString,strResult);
                return null;
            }
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        } finally {
            httpPost.releaseConnection();
        }
        return strResult;
    }
    /**
     * json参数方式POST提交
     *
     * @param url
     * @param jsonString
     * @return
     */
    public static HttpResponse doPostRaw(String url, String jsonString) throws IOException {
        HttpPost httpPost = new HttpPost(url);
        httpPost.addHeader("Content-Type", "application/json;charset=utf-8"); //添加请求头
        try {
            httpPost.setEntity(new StringEntity(jsonString, "utf-8"));
            return HTTP_CLIENT.execute(httpPost);
        } finally {
            httpPost.releaseConnection();
        }
    }
    /**
     * 请求post,包括头信息
     * @param url
     * @param jsonString
     * @param header
     * @return
     */
    public static String doPost(String url, String jsonString,Map<String,Object> header) {
        String strResult = "";
        HttpPost httpPost = new HttpPost(url);
        httpPost.addHeader("Content-Type", "application/json;charset=utf-8"); //添加请求头
        if(header !=null){
            Iterator<Map.Entry<String,Object>> iterator = header.entrySet().iterator();
            while(iterator.hasNext()){
                Map.Entry<String,Object> entry = iterator.next();
                httpPost.addHeader(entry.getKey(),String.valueOf(entry.getValue()));
            }
        }
        try {
            httpPost.setEntity(new StringEntity(jsonString, "utf-8"));
            HttpResponse resp = HTTP_CLIENT.execute(httpPost);
            HttpEntity respEntity = resp.getEntity();
            strResult = EntityUtils.toString(respEntity, "UTF-8");
            int statusCode = resp.getStatusLine().getStatusCode();
            if (statusCode != HttpsURLConnection.HTTP_OK){
                log.error("http post error url:{},params:{},result:{}",url,jsonString,strResult);
                return null;
            }
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        } finally {
            httpPost.releaseConnection();
        }
        return strResult;
    }

    /**
     * Description 输入流转为字节数组
     *
     * @param inStream 输入流
     * @return byte[]
     * @author ZhangChaoFu(zhangchaofu @ jd.com)
     * @date 2019-11-06
     */
    public static byte[] inputStream2byte(InputStream inStream)
            throws IOException {
        ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
        byte[] buff = new byte[1024];
        int rc = 0;
        int len = 100;
        while ((rc = inStream.read(buff, 0, len)) > 0) {
            swapStream.write(buff, 0, rc);
        }
        return swapStream.toByteArray();
    }

    /**
     * Description 获取图片文件
     *
     * @param imgUrl 图片地址
     * @return byte[]
     * @author ZhangChaoFu(zhangchaofu @ jd.com)
     * @date 2019-11-06
     */
    public static byte[] getHttpGetImg(String imgUrl) throws Exception {
        byte[] imageBytes = null;
        URL url = new URL(imgUrl);
        URLConnection urlConnection = url.openConnection();
        if (urlConnection instanceof HttpURLConnection) {
            HttpURLConnection conn = (HttpURLConnection) urlConnection;

            conn.setRequestMethod("GET");
            conn.setConnectTimeout(5 * 1000 * 20);
            InputStream inputStream = conn.getInputStream();
            //通过输入流获取图片数据
            imageBytes = inputStream2byte(inputStream);
        }
        return imageBytes;
    }

    /**
     * RequestEntity
     * Http请求参数太多,封装一下
     *
     * @author sunbin
     * @date 2019/7/9
     */
    @Data
    private static class RequestEntity {
        /**
         * 请求地址
         */
        private String url;
        /**
         * 请求参数
         */
        private Map<String, String> params;
        /**
         * 请求头
         */
        private Map<String, String> header;
        /**
         * 连接超时时间
         */
        private Integer connectionTimeout;
        /**
         * socket超时时间
         */
        private Integer socketTimeout;
        /**
         * 链接请求超时时间
         */
        private Integer connectionRequestTimeout;
    }
    /**
     * 验证外网URL有效性
     * @param url
     * @param methodEnum
     * @return
     */
    public static boolean validateUrl(String url,HttpMethodEnum methodEnum){
        return true;
//        try {
//
//            // 定义请求协议白名单列表
//            String[] allowProtocols = new String[]{"http", "https"};
//            boolean  protocolCheck = false;
//            URL urlObj = null;
//            try {
//                urlObj = new URL(url);
//            } catch (Exception e) {// 拒绝处理//
//                log.error(e.getMessage(),e);
//                return false;
//            }
//            // 首先进行协议校验
//            String protocol = urlObj.getProtocol();
//            for (String item : allowProtocols) {
//                if (protocol.equals(item)) {
//                    protocolCheck = true;
//                    break;
//                }
//            }
//            if (!protocolCheck){
//                log.error("URL协议错误!url={}",url);
//                return false;
//            }
//            if (protocol.equals("https")){
//                detourHttps();
//            }
//            // 设置此类是否应该自动执行 HTTP重定向(响应代码为 3xx 的请求)。
//            HttpURLConnection.setFollowRedirects(true);
//            // 到URL所引用的远程对象的连接
//            HttpURLConnection conn = null;
//            URLConnection urlConnection = urlObj.openConnection();
//            if (urlConnection instanceof HttpURLConnection) {
//                conn = (HttpURLConnection) urlConnection;
//            } else {
//                log.error("URLConnection open false url:"+url);
//                return false;
//            }
//            // 设置URL请求的方法,GET POST HEAD OPTIONS PUT DELETE TRACE
//            // 以上方法之一是合法的,具体取决于协议的限制。
//            conn.setRequestMethod(methodEnum.name());
//            // 从HTTP响应消息获取状态码
//            if (conn.getResponseCode() == HttpURLConnection.HTTP_OK || conn.getResponseCode() == HttpURLConnection.HTTP_MOVED_TEMP){
//                return true;
//            }else {
//                log.error("conn.getResponseCode() is not 200 ResponseCode:{},url:{}",conn.getResponseCode(),url);
//                return false;
//            }
//        } catch (Exception e) {
//            log.error(e.getMessage(),e);
//            return false;
//        }
    }


    /**
     * 验证外网URL有效性(更宽泛的校验 放过2XX 3XX)
     * @param url
     * @param methodEnum
     * @return
     */
    public static boolean validateUrlWidth(String url,HttpMethodEnum methodEnum){
        try {

            // 定义请求协议白名单列表
            String[] allowProtocols = new String[]{"http", "https"};
            boolean  protocolCheck = false;
            URL urlObj = null;
            try {
                urlObj = new URL(url);
            } catch (Exception e) {// 拒绝处理//
                log.error(e.getMessage(),e);
                return false;
            }
            // 首先进行协议校验
            String protocol = urlObj.getProtocol();
            for (String item : allowProtocols) {
                if (protocol.equals(item)) {
                    protocolCheck = true;
                    break;
                }
            }
            if (!protocolCheck){
                log.error("URL协议错误!url={}",url);
                return false;
            }
            if (protocol.equals("https")){
                detourHttps();
            }
            // 设置此类是否应该自动执行 HTTP重定向(响应代码为 3xx 的请求)。
            HttpURLConnection.setFollowRedirects(true);
            // 到URL所引用的远程对象的连接
            HttpURLConnection conn = null;
            URLConnection urlConnection = urlObj.openConnection();
            if (urlConnection instanceof HttpURLConnection) {
                conn = (HttpURLConnection) urlConnection;
            } else {
                log.error("URLConnection open false url:"+url);
                return false;
            }
            // 设置URL请求的方法,GET POST HEAD OPTIONS PUT DELETE TRACE
            // 以上方法之一是合法的,具体取决于协议的限制。
            conn.setRequestMethod(methodEnum.name());
            // 从HTTP响应消息获取状态码
            if (conn.getResponseCode()>= HttpURLConnection.HTTP_OK && conn.getResponseCode()<HttpURLConnection.HTTP_BAD_REQUEST){
                return true;
            }else {
                log.error("conn.getResponseCode() is not 200 ResponseCode:{},url:{}",conn.getResponseCode(),url);
                return false;
            }
        } catch (Exception e) {
            log.error(e.getMessage(),e);
            return false;
        }
    }

    /**
     * 由于引入了安全部加密SDK TDEClient,该类初始化时会加载自己的证书,影响系统证书读取,在发起https请求之前需要修正系统SSL配置
     */
    public static void detourHttps(){

        TrustManager[] trustAllCerts;

        try {

            trustAllCerts = new TrustManager[]{new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[]{};
                }

                public void checkClientTrusted(X509Certificate[] chain, String authType)
                        throws CertificateException {
                }

                public void checkServerTrusted(X509Certificate[] chain, String authType)
                        throws CertificateException {
                }
            }};
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

            // Create all-trusting host name verifier
            HostnameVerifier allHostsValid = new HostnameVerifier() {
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            };

            // Install the all-trusting host verifier
            HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

上次编辑于:
贡献者: ext.liyuanhao3