All Downloads are FREE. Search and download functionalities are using the official Maven repository.

eleme.openapi.sdk.utils.WebUtils Maven / Gradle / Ivy

There is a newer version: 1.30.71
Show newest version
package eleme.openapi.sdk.utils;

import com.fasterxml.jackson.databind.JavaType;
import eleme.openapi.sdk.api.exception.*;
import eleme.openapi.sdk.api.protocol.ErrorPayload;
import eleme.openapi.sdk.api.protocol.ResponsePayload;
import eleme.openapi.sdk.config.Constants;
import eleme.openapi.sdk.config.Config;
import eleme.openapi.sdk.oauth.response.Token;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.*;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.*;
import java.io.*;
import java.lang.reflect.Type;
import java.net.*;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.zip.GZIPInputStream;

public abstract class WebUtils {
    private static final String DEFAULT_CHARSET = Constants.CHARSET_UTF8;
    private static final String METHOD_POST = "POST";
    private static final PoolingHttpClientConnectionManager poolingConnManager;
    private static final CloseableHttpClient httpClient;
    public static final int MAX_TOTAL = 200;
    public static final int DEFAULT_PER_ROUTE = 20;

    static {
        try {
            // 创建SSLContextBuilder实例
            SSLContextBuilder builder = new SSLContextBuilder();
            // 信任自签名证书
            builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
            // 使用SSLContextBuilder构建SSLContext
            SSLContext sslContext = builder.build();
            // 创建SSLConnectionSocketFactory实例,使用自签证书的SSLContext和禁用主机名验证
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                    sslContext,
                    NoopHostnameVerifier.INSTANCE
            );
            poolingConnManager = new PoolingHttpClientConnectionManager();
            // 设置连接池的最大连接数
            poolingConnManager.setMaxTotal(MAX_TOTAL);
            // 设置每个路由的默认连接数
            poolingConnManager.setDefaultMaxPerRoute(DEFAULT_PER_ROUTE);

            httpClient = HttpClients.custom()
                    .setSSLSocketFactory(sslsf)
                    .setConnectionManager(poolingConnManager)
                    .build();
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        } catch (KeyStoreException e) {
            throw new RuntimeException(e);
        } catch (KeyManagementException e) {
            throw new RuntimeException(e);
        }
    }

    private static class DefaultTrustManager implements X509TrustManager {
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }

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

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

    public static String doPost(Config context, String url,
                                Map params,
                                String charset,
                                String rid,
                                int connectTimeout,
                                int readTimeout,
                                Map headerMap) throws IOException {
        String ctype = "application/x-www-form-urlencoded;charset=" + charset;
        String query = buildQuery(params, charset);
        setLogInfo(context, "request: " + query);

        byte[] content = {};
        if (query != null) {
            content = query.getBytes(charset);
        }
        return _doPost(context, url, ctype, content, rid, connectTimeout, readTimeout, headerMap);
    }

    public static String doPost(Config context, String url, String ctype, byte[] content, String rid, int connectTimeout, int readTimeout)
            throws SocketTimeoutException, IOException {
        if (content != null && context.isHttpPoolRequest()) {
            return doPostV2(context, url, ctype, content, rid, connectTimeout, readTimeout);
        }
        return _doPost(context, url, ctype, content, rid, connectTimeout, readTimeout, null);
    }
    public static String doPostV2(Config context, String url, String ctype, byte[] content, String rid, int connectTimeout, int readTimeout)
            throws SocketTimeoutException, IOException {
        return doInnerPost(context, url, ctype, content, rid, connectTimeout, readTimeout, null);
    }

    /**
     * 添加相关的 shutdown 方法来释放资源,通常在应用关闭的时候调用
      */
    public static void shutdown() throws IOException {
        httpClient.close();
        poolingConnManager.shutdown();
    }

    public static String doInnerPost(Config context,String url, String ctype, byte[] content, String rid, int connectTimeout, int readTimeout, Map headerMap)
            throws SocketTimeoutException, IOException {
        HttpPost postRequest = new HttpPost(url);
        postRequest.setEntity(new ByteArrayEntity(content));
        postRequest.setConfig(RequestConfig.custom().setConnectTimeout(connectTimeout).setSocketTimeout(readTimeout).build());
        postRequest.setHeader("Accept", "text/xml,text/javascript,text/html");
        postRequest.setHeader("Content-Type", ctype);
        postRequest.setHeader("Accept-Encoding", "gzip");
        postRequest.setHeader("User-Agent", "eleme-openapi-java-sdk");
        postRequest.setHeader("x-eleme-requestid", rid);
        if (headerMap != null) {
            for (Map.Entry entry : headerMap.entrySet()) {
                postRequest.setHeader(entry.getKey(), entry.getValue());
            }
        }
        HttpResponse response = httpClient.execute(postRequest);
        String responseStr = EntityUtils.toString(response.getEntity(), "UTF-8");
        EntityUtils.consume(response.getEntity());
        setLogInfo(context, "response: " + responseStr);
        return responseStr;
    }

    private static String _doPost(Config context, String url, String ctype, byte[] content, String rid, int connectTimeout, int readTimeout,
                                  Map headerMap) throws SocketTimeoutException, IOException {
        HttpURLConnection conn = null;
        OutputStream out = null;
        String rsp = null;
        try {
            conn = getConnection(new URL(url), METHOD_POST, ctype, headerMap, rid);
            conn.setConnectTimeout(connectTimeout);
            conn.setReadTimeout(readTimeout);
            out = conn.getOutputStream();
            out.write(content);
            rsp = getResponseAsString(conn);
        } finally {
            if (out != null) {
                out.close();
            }
            if (conn != null) {
                conn.disconnect();
            }
        }
        setLogInfo(context, "response: " + rsp);
        return rsp;
    }

    private static HttpURLConnection getConnection(URL url, String method, String ctype, Map headerMap, String rid) throws IOException {
        HttpURLConnection conn;
        if ("https".equals(url.getProtocol())) {
            SSLContext ctx;
            try {
                ctx = SSLContext.getInstance("TLS");
                ctx.init(new KeyManager[0], new TrustManager[]{new DefaultTrustManager()}, new SecureRandom());
            } catch (Exception e) {
                throw new IOException(e);
            }
            HttpsURLConnection connHttps = (HttpsURLConnection) url.openConnection();
            connHttps.setSSLSocketFactory(ctx.getSocketFactory());
            connHttps.setHostnameVerifier(new HostnameVerifier() {
                public boolean verify(String hostname, SSLSession session) {
                    return true;// 默认都认证通过
                }
            });
            conn = connHttps;
        } else {
            conn = (HttpURLConnection) url.openConnection();
        }

        conn.setRequestMethod(method);
        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setRequestProperty("Accept", "text/xml,text/javascript,text/html");
        conn.setRequestProperty("Content-Type", ctype);
        conn.setRequestProperty("Accept-Encoding", "gzip");
        conn.setRequestProperty("User-Agent", "eleme-openapi-java-sdk");
        String elemeRequestId = rid;
        conn.setRequestProperty("x-eleme-requestid", elemeRequestId);
        if (headerMap != null) {
            for (Map.Entry entry : headerMap.entrySet()) {
                conn.setRequestProperty(entry.getKey(), entry.getValue());
            }
        }
        return conn;
    }

    public static String buildQuery(Map params, String charset) throws IOException {
        if (params == null || params.isEmpty()) {
            return null;
        }

        StringBuilder query = new StringBuilder();
        Set> entries = params.entrySet();
        boolean hasParam = false;

        for (Map.Entry entry : entries) {
            String name = entry.getKey();
            String value = entry.getValue();
            // 忽略参数名或参数值为空的参数
            if (StringUtils.areNotEmpty(name, value)) {
                if (hasParam) {
                    query.append("&");
                } else {
                    hasParam = true;
                }
                query.append(name).append("=").append(URLEncoder.encode(value, charset));
            }
        }
        return query.toString();
    }

    protected static String getResponseAsString(HttpURLConnection conn) throws IOException {
        String charset = getResponseCharset(conn.getContentType());
        InputStream es = conn.getErrorStream();
        if (es == null) {
            return getStreamAsString(conn.getInputStream(), charset, conn);
        } else {
            String msg = getStreamAsString(es, charset, conn);
            if (StringUtils.isEmpty(msg)) {
                throw new IOException(conn.getResponseCode() + ":" + conn.getResponseMessage());
            } else {
                return msg;
            }
        }
    }

    private static String getStreamAsString(InputStream stream, String charset, HttpURLConnection conn) throws IOException {
        try {
            Reader reader;
            if ("gzip".equals(conn.getContentEncoding())) {
                reader = new InputStreamReader(new GZIPInputStream(stream), charset);
            } else {
                reader = new InputStreamReader(stream, charset);
            }

            StringBuilder response = new StringBuilder();
            final char[] buff = new char[1024];
            int read = 0;
            while ((read = reader.read(buff)) > 0) {
                response.append(buff, 0, read);
            }

            return response.toString();
        } finally {
            if (stream != null) {
                stream.close();
            }
        }
    }

    public static String getReqID() {
        String reqId = generateUUID() + "|" + System.currentTimeMillis();
        return reqId;
    }

    public static String generateUUID() {
        try {
            String uuid = UUID.randomUUID().toString().replaceAll("-", "");
            if (uuid.length() > 32) {
                uuid = uuid.substring(0, 32);
            }
            return uuid.toUpperCase();
        } catch (Exception e) {
            return "00112233445566778899AABBCCDDEEFF";
        }
    }

    private static String getResponseCharset(String ctype) {
        String charset = DEFAULT_CHARSET;

        if (!StringUtils.isEmpty(ctype)) {
            String[] params = ctype.split(";");
            for (String param : params) {
                param = param.trim();
                if (param.startsWith("charset")) {
                    String[] pair = param.split("=", 2);
                    if (pair.length == 2) {
                        if (!StringUtils.isEmpty(pair[1])) {
                            charset = pair[1].trim();
                        }
                    }
                    break;
                }
            }
        }

        return charset;
    }

    public static  T call(Config context, String action,
                             Map parameters,
                             Token token,
                             Type type
    ) throws ServiceException {
        final long timestamp = System.currentTimeMillis();
        final String appKey = context.getApp_key();
        String secret = context.getApp_secret();
        String accessToken = token.getAccessToken();
        String requestId = getReqID();

        System.out.println("requestId: " + requestId);
        Map requestPayload = new HashMap();
        requestPayload.put("nop", "1.0.0");
        requestPayload.put("id", requestId);
        requestPayload.put("action", action);
        requestPayload.put("token", accessToken);

        Map metasHashMap = new HashMap();
        metasHashMap.put("app_key", appKey);
        metasHashMap.put("timestamp", timestamp);

        requestPayload.put("metas", metasHashMap);
        requestPayload.put("params", parameters);
        String signature = SignatureUtil.generateSignature(appKey, secret, timestamp, action, accessToken, parameters);
        requestPayload.put("signature", signature);

        String requestJson = JacksonUtils.obj2json(requestPayload);
        ResponsePayload responsePayload;
        try {
            responsePayload = doRequest(context, requestJson, requestId);
        } catch (SocketTimeoutException ex) {
            throw new SourceTimeoutException();
        } catch (IOException ex) {
            throw new ServiceException(ex.getClass().getName(), ex);
        }
        setLogInfo(context, "request: " + requestJson);
        if (responsePayload != null && null != responsePayload.getError()) {
            ServiceException serviceException = toException(responsePayload.getError());
            if (serviceException != null) {
                setLogError(context, "error: " + serviceException.getMessage());
                throw serviceException;
            }
            throw new ServerErrorException();
        }
        if (type == void.class)
            return null;
        String s2 = JacksonUtils.obj2json(responsePayload.getResult());
        JavaType javaType = JacksonUtils.getInstance().getTypeFactory().constructType(type);
        return JacksonUtils.json2pojo(s2,javaType);
    }

    private static ResponsePayload doRequest(Config context, String requestJson, String rid) throws SocketTimeoutException, IOException {
        String response = doPost(context, context.getApiUrl(), "application/json; charset=utf-8", requestJson.getBytes(Constants.CHARSET_UTF8), rid, 15000, 15000);
        setLogInfo(context, "response: " + response);
        return JacksonUtils.json2pojo(response, ResponsePayload.class);
    }

    private static ServiceException toException(ErrorPayload error) throws ServiceException {
        String code = error.getCode();
        if(StringUtils.isEmpty(code)) return null;
        String message = error.getMessage();
        if ("ACCESS_DENIED".equals(code))
            return new AccessDeniedException(message);
        if ("EXCEED_LIMIT".equals(code))
            return new ExceedLimitException(message);
        if ("INVALID_SIGNATURE".equals(code))
            return new InvalidSignatureException(message);
        if ("INVALID_TIMESTAMP".equals(code))
            return new InvalidTimestampException(message);
        if ("METHOD_NOT_ALLOWED".equals(code))
            return new MethodNotAllowedException(message);
        if ("PERMISSION_DENIED".equals(code))
            return new PermissionDeniedException(message);
        if ("UNAUTHORIZED".equals(code))
            return new UnauthorizedException(message);
        if ("VALIDATION_FAILED".equals(code))
            return new ValidationFailedException(message);
        if ("BUSINESS_ERROR".equals(code) || code.startsWith("BIZ_")) {
            return new BusinessException(code, error.getMessage());
        }
        return new ServiceException(message);
    }

    private static void setLogInfo(Config context, String msg) {
        if (null != context.getElemeSdkLogger()) {
            context.getElemeSdkLogger().info(msg);
        }
    }

    private static void setLogError(Config context, String msg) {
        if (null != context.getElemeSdkLogger()) {
            context.getElemeSdkLogger().error(msg);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy