/*
 * @(#)HttpClientUtil.java    2012-5-19
 *
 * @Company < www.360buy.com >
 */
package com.jd.jdx.x.sr.cms.domain.wxpay.util;

import static org.apache.commons.httpclient.params.HttpMethodParams.SO_TIMEOUT;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.*;

import com.jd.bk.common.util.json.JsonUtil;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;

import javax.net.ssl.KeyManagerFactory;

/**
 * @version <1.0>
 * @Date <2012-5-19 下午2:32:19>
 * @description < 对HttpClient简单封装  >
 */
public class HttpClientUtils {
    private static final org.apache.logging.log4j.Logger logger = LogManager.getLogger(HttpClientUtils.class);
    /**
     * 默认编码为UTF-8
     */
    private static final String HTTP_CONTENT_CHARSET = "UTF-8";
    public static final Integer MAX_TIME_OUT = 10000;
    public static final Integer MAX_IDLE_TIME_OUT = 60000;
    public static final Integer MAX_CONN = 100;

    public static HttpClient httpClient = null;

    static {
        MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
        connectionManager.closeIdleConnections(MAX_IDLE_TIME_OUT);
        connectionManager.getParams().setParameter("http.connection-manager.max-total", MAX_CONN);
        httpClient = new HttpClient(connectionManager);
        httpClient.getParams().setParameter(SO_TIMEOUT, MAX_TIME_OUT);
        httpClient.getParams().setParameter("http.connection.timeout", MAX_TIME_OUT);
        httpClient.getParams().setParameter("http.connection-manager.timeout", MAX_TIME_OUT.longValue());
    }

    /**
     * 发送HTTP请求  目前没有加入重复调用,业务需要可以再次加上
     *
     * @param url
     * @param param
     * @return HTTP响应
     */
    public static String sendPostRequest(String url, Map<String, Object> param) {
        // HTTP方法,还有get,head,put,delete,connect,options(询问可用的选项)  
        PostMethod post = new PostMethod(url);
        post.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, HTTP_CONTENT_CHARSET);
        String contentType = "application/json;charset=UTF-8";
        post.setRequestHeader("Content-Type", contentType);

        /*if (param != null) {
            for (Entry<String, Object> entry : param.entrySet()) {
                if (entry.getValue() != null) {
                    post.addParameter(entry.getKey(), entry.getValue().toString());
                }
            }
        }*/
        try {
//            post.addRequestHeader(new Header("Connection", "close"));  
            // post.addRequestHeader("Cookie", "ID=1"); //添加Cookie  
            post.setRequestBody(JsonUtil3.toJSONString(param));
            httpClient.executeMethod(post);
            if (post.getStatusCode() == HttpStatus.SC_OK) {
                return post.getResponseBodyAsString();
            } else {
                post.abort();
                System.out.println(post.getStatusCode());
                logger.error("Http Comunication error!code-->" + post.getStatusCode());
            }
        } catch (Exception e) {
            logger.error("Http post occur error!url=" + url + ",param=" + param, e);
        } finally {
            post.releaseConnection();
        }
        return null;
    }

    private static String getToken(String method, String url, String body, WechatScorePayPaymentConfig config, PrivateKey key) {
        String nonceStr = CommonUtil.generateUUID32();
        long timestamp = System.currentTimeMillis() / 1000;
        String message = buildMessage(method, url, timestamp, nonceStr, body);
        String signature = null;
        try {
            signature = sign(message.getBytes("utf-8"), key);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            throw new RuntimeException("签名出错");
        }

        return "WECHATPAY2-SHA256-RSA2048 mchid=\"" + config.getMchId() + "\","
                + "nonce_str=\"" + nonceStr + "\","
                + "timestamp=\"" + timestamp + "\","
                + "serial_no=\"" + config.getCertificateSerialNo() + "\","
                + "signature=\"" + signature + "\"";
    }

    private static String sign(byte[] message, PrivateKey key) {
        Signature sign = null;
        String re = null;
        try {
            sign = Signature.getInstance("SHA256withRSA");
            sign.initSign(key);
            sign.update(message);
            re = Base64.getEncoder().encodeToString(sign.sign());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            throw new RuntimeException("构造签名出错");
        } catch (SignatureException e) {
            e.printStackTrace();
            throw new RuntimeException("构造签名出错");
        } catch (InvalidKeyException e) {
            e.printStackTrace();
            throw new RuntimeException("构造签名出错");
        }
        return re;
    }

    private static String buildMessage(String method, String url, long timestamp, String nonceStr, String body) {

        return method + "\n"
                + url + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + body + "\n";
    }


    public static void main(String[] args) {
        System.out.println(buildMessage("method","ll",124341351,"dqtqtqter",""));
    }
    /**
     * post签名验证 v3
     *
     * @param url
     * @param param
     * @param method
     * @param config
     * @return
     */
    public static String sendWechatScorePayPostJsonRequest(String url, String param, String method, WechatScorePayPaymentConfig config) {
        // HTTP方法,还有get,head,put,delete,connect,options(询问可用的选项)
        String canonicalUrl = getUrlRemoveHost(url);
        PostMethod post = new PostMethod(url);
        try {
            PrivateKey key = getPrivateKey(config);

            logger.error("Http Comunication error!config -->[{}],method-->[{}],param-->[{}]" , JsonUtil3.toJSONString(config),method,param);

            String authorizationStr = getToken(method, canonicalUrl, param, config, key);
            post.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, HTTP_CONTENT_CHARSET);
            String contentType = "application/json;charset=UTF-8";
            post.setRequestHeader("Content-Type", contentType);
            post.setRequestHeader("Accept", contentType);
            post.setRequestHeader("Authorization", authorizationStr);
            logger.error("Http Comunication error!Authorization -->[{}]" ,authorizationStr);

            post.setRequestBody(param);
            httpClient.executeMethod(post);
            System.out.println(post.getStatusCode());
            System.out.println(post.getStatusText());
            if (post.getStatusCode() == HttpStatus.SC_OK) {
                return post.getResponseBodyAsString();
            } else {
                post.abort();
                logger.error("Http Comunication error!ret [{}]", JsonUtil.toJson(post));
                logger.error("Http Comunication error!code-->" + post.getStatusCode());
            }
        } catch (Exception e) {
            logger.error("Http post occur error!url=" + url + ",param=" + param, e);
        } finally {
            post.releaseConnection();
        }
        return null;
    }

    /**
     * @param url
     * @param param
     * @param method
     * @param config
     * @return
     */
    public static String sendWechatScorePayPostRequest(String url, Map<String, Object> param, String method, WechatScorePayPaymentConfig config) {
        // HTTP方法,还有get,head,put,delete,connect,options(询问可用的选项)
        PostMethod post = new PostMethod(url);
        try {
            PrivateKey key = getPrivateKey(config);
            String authorizationStr = getToken(method, getUrlRemoveHost(url), JsonUtil3.toJSONString(param), config, key);
            post.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, HTTP_CONTENT_CHARSET);
            String contentType = "application/json;charset=UTF-8";
            post.setRequestHeader("Content-Type", contentType);
            post.setRequestHeader("Accept", contentType);
            post.setRequestHeader("Authorization", authorizationStr);
            post.setRequestBody(JsonUtil3.toJSONString(param));
            httpClient.executeMethod(post);
            if (post.getStatusCode() == HttpStatus.SC_OK) {
                return post.getResponseBodyAsString();
            } else {
                post.abort();
                System.out.println(post.getStatusCode());
                logger.error("Http Comunication error!code-->" + post.getStatusCode());
            }
        } catch (Exception e) {
            logger.error("Http post occur error!url=" + url + ",param=" + param, e);
        } finally {
            post.releaseConnection();
        }
        return null;
    }

    private static PrivateKey getPrivateKey(WechatScorePayPaymentConfig config) throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException {
        InputStream instream;
        URL certUrl = new URL(config.getCertificateAddress());
        HttpURLConnection connection = (HttpURLConnection) certUrl.openConnection();
        //设置超时时间为3秒
        connection.setConnectTimeout(5 * 1000);
        //防止屏蔽程序抓取而返回403错误
        connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36");
        instream = connection.getInputStream();
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        char[] password = config.getMchId().toCharArray();
        try {
            keyStore.load(instream, password);
        } finally {
            instream.close();
        }
        Enumeration en = keyStore.aliases();
        String pName = null;
        while (en.hasMoreElements()) {
            String n = (String) en.nextElement();
            if (keyStore.isKeyEntry(n)) {
                pName = n;
            }
        }
        // 获取证书的私钥
        return (PrivateKey) keyStore.getKey(pName, password);
    }

    /**
     * 发送HTTP请求  目前没有加入重复调用,业务需要可以再次加上
     *
     * @param url
     * @param param
     * @return HTTP响应
     */
    public static String sendPostXMLRequest(String url, Map<String, Object> param) {
        // HTTP方法,还有get,head,put,delete,connect,options(询问可用的选项)
        PostMethod post = new PostMethod(url);
        post.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, HTTP_CONTENT_CHARSET);
        String contentType = "application/xml;charset=UTF-8";
        post.setRequestHeader("Content-Type", contentType);
        try {
            post.setRequestBody(CommonUtil.map2Xml(param));
            httpClient.executeMethod(post);
            if (post.getStatusCode() == HttpStatus.SC_OK) {
                return post.getResponseBodyAsString();
            } else {
                post.abort();
                System.out.println(post.getStatusCode());
                logger.error("Http Comunication error!code-->" + post.getStatusCode());
            }
        } catch (Exception e) {
            logger.error("Http post occur error!url=" + url + ",param=" + param, e);
        } finally {
            post.releaseConnection();
        }
        return null;
    }

    /**
     * 发送HTTP请求
     *
     * @param url
     * @param content
     * @return HTTP响应
     */
    @SuppressWarnings("deprecation")
    public static String sendPostRequest(String url, String content) {
        // HTTP方法,还有get,head,put,delete,connect,options(询问可用的选项)  
        PostMethod post = new PostMethod(url);
        post.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, HTTP_CONTENT_CHARSET);
        if (StringUtils.isNotBlank(content)) {
            post.setRequestBody(content);
        }
        try {
            post.addRequestHeader(new Header("Connection", "close"));
            // post.addRequestHeader("Cookie", "ID=1"); //添加Cookie  
            httpClient.executeMethod(post);
            if (post.getStatusCode() == HttpStatus.SC_OK) {
                return post.getResponseBodyAsString();
            } else {
                post.abort();
                logger.error("Http Comunication error!code-->" + post.getStatusCode());
            }
        } catch (Exception e) {
            logger.error("Http post occur error!url=" + url + ",content=" + content, e);
        } finally {
            post.releaseConnection();
        }
        return null;
    }

    /**
     * 发送HTTP请求
     *
     * @param url
     * @return HTTP响应
     */
    public static String getRequest(String url) {
        // HTTP方法,还有get,head,put,delete,connect,options(询问可用的选项)  
        GetMethod get = new GetMethod(url);
        get.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, HTTP_CONTENT_CHARSET);
        try {
            get.addRequestHeader(new Header("Connection", "close"));
            // post.addRequestHeader("Cookie", "ID=1"); //添加Cookie  
            httpClient.executeMethod(get);
            if (get.getStatusCode() == HttpStatus.SC_OK) {
                return get.getResponseBodyAsString();
            } else {
                get.abort();
                logger.error("Http Comunication error!code-->" + get.getStatusCode());
            }
        } catch (Exception e) {
            logger.error("Http post occur error!url=" + url, e);
        } finally {
            get.releaseConnection();
        }
        return null;
    }


    /**
     * @param url
     * @param param
     * @return
     */
    public static String sendWeChatPost(String url, String param) {
        PrintWriter out = null;
        BufferedReader in = null;
        StringBuilder result = new StringBuilder();
        if (logger.isInfoEnabled()) {
            logger.info("invoke http post[wechat] service, url: [" + url + "]\nparam: [" + param + "]");
        }
        try {
            URL realUrl = new URL(url);
            URLConnection conn = realUrl.openConnection();
            conn.setRequestProperty("Content-Type", "application/xml");
            conn.setDoOutput(true);
            conn.setDoInput(true);
            out = new PrintWriter(conn.getOutputStream());
            out.print(param);
            out.flush();
            in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
        } catch (Exception e) {
            logger.error("invoke http post[wechat] service error, because: [" + e.toString() + "]", e);
            throw new RuntimeException(e);
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                logger.error("invoke http post[wechat] service error, because: [" + e.toString() + "]", e);
            }
            if (out != null) {
                out.close();
            }
        }
        if (logger.isInfoEnabled()) {
            logger.info("invoke http post[wechat] service finished, url: [" + url + "], response: [" + result.toString() + "]");
        }
        return result.toString();
    }

    public static String sendPostMethodFace(String uri, Map<String, String> map, String contentType) throws Exception {
        if (contentType == null) {
            contentType = "application/json;charset=UTF-8";
        }
        String returnStr = "";
        PostMethod post = new PostMethod(uri);
        post.setRequestHeader("Content-Type", contentType);
        List<NameValuePair> nameValuePairs = mapToNameValePair(map);
        for (NameValuePair nameValuePair : nameValuePairs) {
            post.addParameter(nameValuePair);
        }
        post.setDoAuthentication(false);
        post.setRequestHeader("Accept", "application/json");
        HttpClient httpclient = new HttpClient();
        try {
            logger.info("sendPostMethodFace--->begin post...");
            int result = httpclient.executeMethod(post);
            logger.info("sendPostMethodFace--->between post...");
            returnStr = post.getResponseBodyAsString();
            logger.info("sendPostMethodFace--->end post...");
            if (result != HttpStatus.SC_OK) {
                throw new RuntimeException(String.valueOf(post.getStatusCode()) + returnStr);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            post.releaseConnection();
        }
        logger.info("sendPostMethodFace--->end method and return...");
        return returnStr;
    }


    /**
     * map转化到Web参数
     *
     * @param map
     * @return
     */
    private static List<NameValuePair> mapToNameValePair(Map<String, String> map) {
        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
        if (MapUtils.isNotEmpty(map)) {
            for (Map.Entry<String, String> entry : map.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                if (StringUtils.isBlank(key) || StringUtils.isBlank(value)) {
                    continue;
                }
                NameValuePair pair = new NameValuePair(key, value);
                nameValuePairs.add(pair);
            }
        }
        return nameValuePairs;
    }

    public static Map<String, String> getUrlParams(String param) {
        Map<String, String> map = new HashMap<String, String>(0);
        if (StringUtils.isBlank(param)) {
            return map;
        }
        String[] params = param.split("&");
        for (int i = 0; i < params.length; i++) {
            String[] p = params[i].split("=");
            if (p.length == 2) {
                map.put(p[0], p[1]);
            }
        }
        return map;
    }


    /**
     * 发送GET请求
     *
     * @param url    getURL
     * @param params 请求参数
     * @return
     */
    public static String doGet(String url, Map<String, String> params) {

        HttpClient httpCilent = new HttpClient();
        url = getUrl(url, params);

        GetMethod getMethod = new GetMethod(url);
        String content = null;
        try {
            InputStream inputStream = null;
            try {
                if (httpCilent.executeMethod(getMethod) == HttpStatus.SC_OK) {
                    inputStream = getMethod.getResponseBodyAsStream();
                    content = IOUtils.toString(inputStream, "utf-8");
                } else {
                    logger.warn("invoke http get service failed, http code: [{}]", getMethod.getStatusLine());
                }
            } catch (Exception e) {
                logger.error("invoke http get service error, because: [" + e.toString() + "]", e);
            } finally {
                IOUtils.closeQuietly(inputStream);
                getMethod.releaseConnection();
            }
        } catch (Exception e) {
            logger.error("invoke http get service error, because: [" + e.toString() + "]", e);
        } finally {
            getMethod.releaseConnection();
        }

        return content;
    }

    /**
     * 发送GET请求
     *
     * @param url    getURL
     * @param params 请求参数
     * @return
     */
    public static String doGetForScorePay(String url, String canonicalUrl, Map<String, String> params, String method, WechatScorePayPaymentConfig config) {

        HttpClient httpCilent = new HttpClient();
        url = getUrl(url, params);


        GetMethod getMethod = new GetMethod(url);
        String content = null;
        try {
            PrivateKey key = getPrivateKey(config);
            String authorizationStr = getToken(method, getUrlRemoveHost(url), "", config, key);
            String contentType = "application/json;charset=UTF-8";
            getMethod.setRequestHeader("Content-Type", contentType);
            getMethod.setRequestHeader("Accept", contentType);
            getMethod.setRequestHeader("Authorization", authorizationStr);
            InputStream inputStream = null;
            try {
                if (httpCilent.executeMethod(getMethod) == HttpStatus.SC_OK) {
                    inputStream = getMethod.getResponseBodyAsStream();
                    content = IOUtils.toString(inputStream, "utf-8");
                } else {
                    logger.warn("invoke http get service failed, ret [{}]", JsonUtil3.toJSONString(getMethod));
                    logger.warn("invoke http get service failed, http code: [{}]", getMethod.getStatusLine());
                }
            } catch (Exception e) {
                logger.error("invoke http get service error, because: [" + e.toString() + "]", e);
            } finally {
                IOUtils.closeQuietly(inputStream);
                getMethod.releaseConnection();
            }
        } catch (Exception e) {
            logger.error("invoke http get service error, because: [" + e.toString() + "]", e);
        } finally {
            getMethod.releaseConnection();
        }

        return content;
    }

    /**
     * getUrl:获取. <br/>
     *
     * @param url          请求地址
     * @param parameterMap 请求参数
     * @return
     */
    private static String getUrl(String url, Map<String, String> parameterMap) {
        if (parameterMap == null || parameterMap.size() == 0) {
            return url;
        }

        // 设置请求参数 // 采用更有效率的entryset modified by  gaotianlin
        if (url.indexOf("?") == -1) {
            url += "?";
        }
        StringBuffer bf = new StringBuffer(url);
        for (Map.Entry<String, String> key : parameterMap.entrySet()) {
            bf.append("&");
            bf.append(key.getKey());
            bf.append("=");
            bf.append(key.getValue());
        }
        return bf.toString();
    }

    private static String getUrlRemoveHost(String url) {
        //String url="https://api.mch.weixin.qq.com/v3/payscore/serviceorder";
        String[] split = url.split("/");
        String res = "";
        for (int i = 0; i < split.length; i++) {
            if (i >= 3) {
                res += "/" + split[i];
            }
            System.out.println(split[i]);
        }
        return res;
    }
}

 

posted on 2020-05-18 14:54  王洪洪  阅读(303)  评论(0编辑  收藏  举报