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

ars.invoke.channel.http.Https Maven / Gradle / Ivy

The newest version!
package ars.invoke.channel.http;

import java.io.File;
import java.io.Reader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.OutputStreamWriter;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import java.util.List;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.regex.Pattern;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.net.URLEncoder;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.nio.channels.ReadableByteChannel;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import javax.swing.text.html.parser.ParserDelegator;
import javax.swing.text.html.HTMLEditorKit.ParserCallback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.util.EntityUtils;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.entity.mime.content.ByteArrayBody;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import ars.util.Nfile;
import ars.util.Files;
import ars.util.Jsons;
import ars.util.Streams;
import ars.util.Strings;
import ars.invoke.remote.Node;
import ars.invoke.remote.Protocol;

/**
 * Http操作工具类
 *
 * @author wuyongqiang
 */
public final class Https {
    /**
     * 应用根资源地址
     */
    public static final String ROOT_URI = "/";

    /**
     * 应用根路径
     */
    public static final String ROOT_PATH;

    /**
     * Html标本标签正则表达匹配对象
     */
    public static final Pattern SCRIPT_PATTERN = Pattern.compile("]*?>[\\s\\S]*?<\\/script>",
        Pattern.CASE_INSENSITIVE);

    /**
     * Html解析器
     */
    private static ParserDelegator parserDelegator;

    /**
     * 客户端连接管理器
     */
    private static ClientConnectionManager manager;

    private static final Logger logger = LoggerFactory.getLogger(Https.class);

    static {
        ROOT_PATH = new File(Strings.CURRENT_PATH).getParentFile().getParentFile().getPath();
    }

    /**
     * HTTP协议请求方式
     *
     * @author wuyongqiang
     */
    public enum Method {
        /**
         * HEAD方式
         */
        HEAD,

        /**
         * GET方式
         */
        GET,

        /**
         * POST方式
         */
        POST,

        /**
         * PUT方式
         */
        PUT,

        /**
         * DELETE方式
         */
        DELETE,

        /**
         * TRACE方式
         */
        TRACE,

        /**
         * CONNECT方式
         */
        CONNECT,

        /**
         * OPTIONS方式
         */
        OPTIONS;

    }

    /**
     * 资源地址上下文标识
     */
    public static final String CONTEXT_URI = "uri";

    /**
     * 资源地址全路径上下问标识
     */
    public static final String CONTEXT_URL = "url";

    /**
     * 客户地址上下文标识
     */
    public static final String CONTEXT_HOST = "host";

    /**
     * 系统路径上下文标识
     */
    public static final String CONTEXT_PATH = "path";

    /**
     * 请求令牌上下文标识
     */
    public static final String CONTEXT_TOKEN = "token";

    /**
     * 请求客户端上下文标识
     */
    public static final String CONTEXT_CLIENT = "client";

    /**
     * 请求协议上下文标识
     */
    public static final String CONTEXT_SCHEME = "scheme";

    /**
     * 请求域名上下文标识
     */
    public static final String CONTEXT_DOMAIN = "domain";

    /**
     * 主机地址上下文标识
     */
    public static final String CONTEXT_SERVER = "server";

    /**
     * 请求端口号上下文标识
     */
    public static final String CONTEXT_PORT = "port";

    /**
     * 请求参数上下文标识
     */
    public static final String CONTEXT_REQUEST = "request";

    /**
     * 请求会话上下文标识
     */
    public static final String CONTEXT_SESSION = "session";

    /**
     * 请求内容上下文标识
     */
    public static final String CONTEXT_CONTENT = "content";

    /**
     * 请求响应上下文标识
     */
    public static final String CONTEXT_RESPONSE = "response";

    /**
     * 日期时间上下文标识
     */
    public static final String CONTEXT_DATETIME = "datetime";

    /**
     * 当前请求上下文标识
     */
    public static final String CONTEXT_EXECUTOR = "executor";

    /**
     * 请求时间戳上下文标识
     */
    public static final String CONTEXT_TIMESTAMP = "timestamp";

    /**
     * 请求耗时上下文标识
     */
    public static final String CONTEXT_TIMESPEND = "timespend";

    private Https() {

    }

    /**
     * 获取客户端连接管理器
     *
     * @return 客户端连接管理器
     */
    public static ClientConnectionManager getManager() {
        if (manager == null) {
            synchronized (Https.class) {
                if (manager == null) {
                    logger.info("Initialization default http client connection manager with class {}",
                        PoolingClientConnectionManager.class.getName());
                    manager = new PoolingClientConnectionManager();
                }
            }
        }
        return manager;
    }

    /**
     * 设置客户端连接管理器
     *
     * @param manager 客户端连接管理器
     */
    public static void setManager(ClientConnectionManager manager) {
        if (manager == null) {
            throw new IllegalArgumentException("ClientConnectionManager must not be null");
        }
        if (Https.manager != null) {
            throw new IllegalStateException("ClientConnectionManager already initialized");
        }
        synchronized (Https.class) {
            if (Https.manager == null) {
                Https.manager = manager;
            }
        }
    }

    /**
     * 获取Http客户端对象
     *
     * @return Http客户端对象
     */
    public static HttpClient getClient() {
        return getClient(false);
    }

    /**
     * 获取Http客户端对象
     *
     * @param encrypt 是否为加密协议
     * @return Http客户端对象
     */
    public static HttpClient getClient(boolean encrypt) {
        DefaultHttpClient client = new DefaultHttpClient(getManager());
        if (encrypt) {
            bindSSL(client);
        }
        client.setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler(0, false));
        return client;
    }

    /**
     * 绑定SSL,默认使用443端口
     *
     * @param client Http客户端对象
     */
    public static void bindSSL(HttpClient client) {
        bindSSL(client, 443);
    }

    /**
     * 绑定SSL
     *
     * @param client Http客户端对象
     * @param port   端口号
     */
    public static void bindSSL(HttpClient client, int port) {
        if (client == null) {
            throw new IllegalArgumentException("HttpClient must not be null");
        }
        X509TrustManager trustManager = new X509TrustManager() {
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

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

            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
        try {
            SSLContext context = SSLContext.getInstance("TLS");
            context.init(null, new TrustManager[]{trustManager}, null);
            Scheme scheme = new Scheme("https", port,
                new SSLSocketFactory(context, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER));
            client.getConnectionManager().getSchemeRegistry().register(scheme);
        } catch (KeyManagementException e) {
            throw new RuntimeException(e);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取Cookie
     *
     * @param request Http请求对象
     * @param name    Cookie名称
     * @return Cookie值
     */
    public static String getCookie(HttpServletRequest request, String name) {
        if (request == null) {
            throw new IllegalArgumentException("HttpServletRequest must not be null");
        }
        if (name == null) {
            throw new IllegalArgumentException("Name must not be null");
        }
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : request.getCookies()) {
                if (cookie.getName().equals(name)) {
                    try {
                        String value = URLDecoder.decode(cookie.getValue(), Strings.UTF8);
                        return value == null || value.isEmpty() ? null : value;
                    } catch (UnsupportedEncodingException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
        return null;
    }

    /**
     * 设置Cookie
     *
     * @param response Http响应对象
     * @param name     Cookie名称
     * @param value    Cookie值
     * @param timeout  过期时间(秒)
     */
    public static void setCookie(HttpServletResponse response, String name, String value, int timeout) {
        if (response == null) {
            throw new IllegalArgumentException("HttpServletResponse must not be null");
        }
        if (name == null) {
            throw new IllegalArgumentException("Name must not be null");
        }
        if (timeout < 0) {
            throw new IllegalArgumentException("Timeout must not be leass than 0, got " + timeout);
        }
        try {
            Cookie cookie = new Cookie(name,
                value == null ? Strings.EMPTY_STRING : URLEncoder.encode(value, Strings.UTF8));
            cookie.setPath("/");
            cookie.setMaxAge(timeout);
            response.addCookie(cookie);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取并删除Cookie
     *
     * @param request  Http请求对象
     * @param response Http响应对象
     * @param name     Cookie名称
     * @return Cookie值
     */
    public static String removeCookie(HttpServletRequest request, HttpServletResponse response, String name) {
        if (request == null) {
            throw new IllegalArgumentException("HttpServletRequest must not be null");
        }
        if (response == null) {
            throw new IllegalArgumentException("HttpServletResponse must not be null");
        }
        if (name == null) {
            throw new IllegalArgumentException("Name must not be null");
        }
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : request.getCookies()) {
                if (cookie.getName().equals(name)) {
                    try {
                        return URLDecoder.decode(cookie.getValue(), Strings.UTF8);
                    } catch (UnsupportedEncodingException e) {
                        throw new RuntimeException(e);
                    } finally {
                        cookie.setMaxAge(0);
                        response.addCookie(cookie);
                    }
                }
            }
        }
        return null;
    }

    /**
     * 获取远程节点访问地址
     *
     * @param node 远程节点对象
     * @return 远程节点访问地址
     */
    public static String getUrl(Node node) {
        return getUrl(node, null);
    }

    /**
     * 获取远程节点访问地址
     *
     * @param node 远程节点对象
     * @param uri  远程节点资源地址
     * @return 远程节点访问地址
     */
    public static String getUrl(Node node, String uri) {
        if (node == null) {
            throw new IllegalArgumentException("Node must not be null");
        }
        return getUrl(node.getProtocol(), node.getHost(), node.getPort(), uri);
    }

    /**
     * 获取请求资源地址(不包含应用上下文地址)
     *
     * @param request HTTP请求对象
     * @return 资源地址
     */
    public static String getUri(HttpServletRequest request) {
        if (request == null) {
            throw new IllegalArgumentException("HttpServletRequest must not be null");
        }
        String uri = request.getRequestURI();
        String context = request.getContextPath();
        return context == null ? uri : uri.substring(context.length());
    }

    /**
     * 获取HTTP请求的URL地址(不包含资源地址)
     *
     * @param request HTTP请求对象
     * @return URL地址
     */
    public static String getUrl(HttpServletRequest request) {
        if (request == null) {
            throw new IllegalArgumentException("HttpServletRequest must not be null");
        }
        StringBuilder url = new StringBuilder(request.getScheme()).append("://").append(request.getServerName())
            .append(':').append(request.getServerPort());
        String context = request.getContextPath();
        return context == null ? url.toString() : url.append(context).toString();
    }

    /**
     * 获取HTTP URL地址
     *
     * @param protocol 请求协议
     * @param host     请求域名
     * @param port     请求端口
     * @param uri      请求资源路径
     * @return URL地址
     */
    public static String getUrl(Protocol protocol, String host, int port, String uri) {
        if (protocol == null) {
            throw new IllegalArgumentException("Protocol must not be null");
        } else if (protocol != Protocol.http && protocol != Protocol.https) {
            throw new IllegalArgumentException("Not support protocol:" + protocol);
        }
        if (host == null) {
            throw new IllegalArgumentException("Host must not be null");
        }
        StringBuilder url = new StringBuilder(protocol.toString()).append("://").append(host).append(':').append(port);
        if (uri == null || uri.isEmpty()) {
            return url.toString();
        } else if (uri.charAt(0) == '/') {
            return url.append(uri).toString();
        }
        return url.append('/').append(uri).toString();
    }

    /**
     * 将参数字符串形式转换成键/值映射
     *
     * @param param 参数字符串形式
     * @return 键/值映射
     */
    @SuppressWarnings("unchecked")
    public static Map parseParam(String param) {
        if (Strings.isEmpty(param)) {
            return new HashMap(0);
        }
        String[] setions = Strings.split(param, '&');
        Map parameters = new HashMap(setions.length);
        for (String setion : setions) {
            setion = setion.trim();
            if (setion.isEmpty()) {
                continue;
            }
            String[] kv = Strings.split(setion, '=');
            String key = kv[0].trim();
            if (key.isEmpty()) {
                continue;
            }
            String value = kv.length > 1 ? kv[1].trim() : null;
            Object exist = parameters.get(key);
            if (exist == null) {
                parameters.put(key, value);
            } else if (value != null) {
                if (exist instanceof List) {
                    ((List) exist).add(value);
                } else {
                    List list = new LinkedList();
                    list.add((String) exist);
                    list.add(value);
                    parameters.put(key, list);
                }
            }
        }
        return parameters;
    }

    /**
     * 获取URL参数
     *
     * @param url 资源地址
     * @return 参数键/值映射
     */
    public static Map getParameters(String url) {
        int index = url == null ? -1 : url.indexOf('?');
        return index < 0 ? new HashMap(0) : parseParam(url.substring(index + 1));
    }

    /**
     * 获取普通表单请求参数
     *
     * @param request HTTP请求对象
     * @return 参数键/值表
     * @throws IOException IO操作异常
     */
    public static Map getParameters(HttpServletRequest request) throws IOException {
        if (request == null) {
            throw new IllegalArgumentException("HttpServletRequest must not be null");
        }
        Map parameters = new HashMap();
        Enumeration names = request.getParameterNames();
        while (names.hasMoreElements()) {
            String name = names.nextElement();
            Object value = null;
            String[] values = request.getParameterValues(name);
            if (values.length == 1) {
                String param = values[0].trim();
                if (!param.isEmpty()) {
                    value = param;
                }
            } else {
                List _values = new ArrayList(values.length);
                for (int i = 0; i < values.length; i++) {
                    String param = values[i].trim();
                    if (!param.isEmpty()) {
                        _values.add(param);
                    }
                }
                if (_values.size() == 1) {
                    value = _values.get(0);
                } else if (!_values.isEmpty()) {
                    value = _values;
                }
            }
            parameters.put(name, value);
        }
        return parameters;
    }

    /**
     * 获取文件上传表单参数
     *
     * @param request  HTTP请求对象
     * @param uploader 文件上传处理器
     * @return 参数键/值表
     * @throws IOException         IO操作异常
     * @throws FileUploadException 文件上传异常
     */
    @SuppressWarnings("unchecked")
    public static Map getUploadParameters(HttpServletRequest request, ServletFileUpload uploader)
        throws IOException, FileUploadException {
        if (request == null) {
            throw new IllegalArgumentException("HttpServletRequest must not be null");
        }
        if (uploader == null) {
            throw new IllegalArgumentException("ServletFileUpload must not be null");
        }
        List items = uploader.parseRequest(request);
        Map parameters = new HashMap(items.size());
        for (int i = 0; i < items.size(); i++) {
            final FileItem item = (FileItem) items.get(i);
            Object value = null;
            String name = item.getFieldName();
            if (item.isFormField()) {
                String param = new String(item.get(), Strings.UTF8).trim();
                if (!param.isEmpty()) {
                    value = param;
                }
            } else {
                final File file = ((DiskFileItem) item).getStoreLocation();
                value = new Nfile(Files.getName(item.getName())) {
                    private static final long serialVersionUID = 1L;

                    @Override
                    public long getSize() {
                        return item.getSize();
                    }

                    @Override
                    public boolean isFile() {
                        return file.exists();
                    }

                    @Override
                    public File getFile() {
                        return file;
                    }

                    @Override
                    public InputStream getInputStream() throws IOException {
                        return item.getInputStream();
                    }

                };
            }
            Object o = parameters.get(name);
            if (o == null) {
                parameters.put(name, value);
            } else if (value != null) {
                if (o instanceof List) {
                    ((List) o).add(value);
                } else {
                    List values = new LinkedList();
                    values.add(o);
                    values.add(value);
                    parameters.put(name, values);
                }
            }
        }
        return parameters;
    }

    /**
     * 获取请求流参数(参数必须满足JSON格式)
     *
     * @param request HTTP请求对象
     * @return 参数键/值表
     * @throws IOException IO操作异常
     */
    @SuppressWarnings("unchecked")
    public static Map getStreamParameters(HttpServletRequest request) throws IOException {
        if (request == null) {
            throw new IllegalArgumentException("HttpServletRequest must not be null");
        }
        byte[] bytes = null;
        InputStream is = request.getInputStream();
        try {
            bytes = Streams.getBytes(is);
        } finally {
            is.close();
        }
        String json = new String(bytes);
        return json.isEmpty() ? Collections.emptyMap() : (Map) Jsons.parse(json);
    }

    /**
     * 获取Http请求实体
     *
     * @param parameters 请求参数
     * @return 请求实体
     * @throws IOException IO操作异常
     */
    public static HttpEntity getHttpEntity(Map parameters) throws IOException {
        if (parameters == null || parameters.isEmpty()) {
            return null;
        }
        Collection values = parameters.values();
        for (Object value : values) {
            if (value instanceof File || value instanceof Nfile) {
                return getUploadEntity(parameters);
            } else if (value instanceof Object[]) {
                for (Object object : (Object[]) value) {
                    if (object instanceof File || object instanceof Nfile) {
                        return getUploadEntity(parameters);
                    }
                }
            } else if (value instanceof Collection) {
                for (Object object : (Collection) value) {
                    if (object instanceof File || object instanceof Nfile) {
                        return getUploadEntity(parameters);
                    }
                }
            }
        }
        return getPostEntity(parameters);
    }

    /**
     * 获取Get请求参数
     *
     * @param parameters 请求参数
     * @return 参数字符串形式
     * @throws IOException IO操作异常
     */
    public static String getGetEntity(Map parameters) throws IOException {
        return getGetEntity(parameters, Charset.defaultCharset());
    }

    /**
     * 获取Get请求参数
     *
     * @param parameters 请求参数
     * @param charset    编码字符集(如果为空则不对参数进行编码处理)
     * @return 参数字符串形式
     * @throws IOException IO操作异常
     */
    public static String getGetEntity(Map parameters, Charset charset) throws IOException {
        if (parameters == null || parameters.isEmpty()) {
            return null;
        }
        StringBuilder buffer = new StringBuilder();
        for (Entry entry : parameters.entrySet()) {
            String key = entry.getKey();
            if (key == null || key.isEmpty()) {
                continue;
            }
            if (buffer.length() > 0) {
                buffer.append('&');
            }
            Object value = entry.getValue();
            if (value instanceof Object[]) {
                Object[] array = (Object[]) value;
                if (array.length == 0) {
                    buffer.append(key).append('=');
                } else {
                    for (int i = 0; i < array.length; i++) {
                        if (i > 0) {
                            buffer.append('&');
                        }
                        String str = Strings.toString(array[i]);
                        if (charset != null) {
                            str = URLEncoder.encode(str, charset.name());
                        }
                        buffer.append(key).append('=').append(str);
                    }
                }
            } else if (value instanceof Collection) {
                Collection collection = (Collection) value;
                if (collection.isEmpty()) {
                    buffer.append(key).append('=');
                } else {
                    int i = 0;
                    for (Object v : collection) {
                        if (i++ > 0) {
                            buffer.append('&');
                        }
                        String str = Strings.toString(v);
                        if (charset != null) {
                            str = URLEncoder.encode(str, charset.name());
                        }
                        buffer.append(key).append('=').append(str);
                    }
                }
            } else if (value == null) {
                buffer.append(key).append('=');
            } else {
                String str = Strings.toString(value);
                if (charset != null) {
                    str = URLEncoder.encode(str, charset.name());
                }
                buffer.append(key).append('=').append(str);
            }
        }
        return buffer.length() == 0 ? null : buffer.toString();
    }

    /**
     * 获取普通表单请求实例
     *
     * @param parameters 请求参数
     * @return 表单请求实例
     */
    public static UrlEncodedFormEntity getPostEntity(Map parameters) {
        return getPostEntity(parameters, Charset.defaultCharset());
    }

    /**
     * 获取普通表单请求实例
     *
     * @param parameters 请求参数
     * @param charset    编码字符集
     * @return 表单请求实例
     */
    public static UrlEncodedFormEntity getPostEntity(Map parameters, Charset charset) {
        if (parameters == null || parameters.isEmpty()) {
            return null;
        }
        List pairs = new LinkedList();
        for (Entry entry : parameters.entrySet()) {
            String key = entry.getKey();
            if (key == null || key.isEmpty()) {
                continue;
            }
            Object value = entry.getValue();
            if (value instanceof Object[]) {
                Object[] array = (Object[]) value;
                if (array.length == 0) {
                    pairs.add(new BasicNameValuePair(key, Strings.EMPTY_STRING));
                } else {
                    for (Object v : array) {
                        pairs.add(new BasicNameValuePair(key, Strings.toString(v)));
                    }
                }
            } else if (value instanceof Collection) {
                Collection collection = (Collection) value;
                if (collection.isEmpty()) {
                    pairs.add(new BasicNameValuePair(key, Strings.EMPTY_STRING));
                } else {
                    for (Object v : collection) {
                        pairs.add(new BasicNameValuePair(key, Strings.toString(v)));
                    }
                }
            } else if (value == null) {
                pairs.add(new BasicNameValuePair(key, Strings.EMPTY_STRING));
            } else {
                pairs.add(new BasicNameValuePair(key, Strings.toString(value)));
            }
        }
        return new UrlEncodedFormEntity(pairs, charset);
    }

    /**
     * 获取文件上传请求实例
     *
     * @param parameters 请求参数
     * @return 文件上传请求实例
     * @throws IOException IO操作异常
     */
    public static MultipartEntity getUploadEntity(Map parameters) throws IOException {
        return getUploadEntity(parameters, Charset.defaultCharset());
    }

    /**
     * 获取文件上传请求实例
     *
     * @param parameters 请求参数
     * @param charset    编码字符集
     * @return 文件上传请求实例
     * @throws IOException IO操作异常
     */
    public static MultipartEntity getUploadEntity(Map parameters, Charset charset) throws IOException {
        if (parameters == null || parameters.isEmpty()) {
            return null;
        }
        MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE, null, charset);
        for (Entry entry : parameters.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            if (value == null) {
                entity.addPart(key, new StringBody(Strings.EMPTY_STRING));
            } else if (value instanceof File) {
                entity.addPart(key, new FileBody((File) value));
            } else if (value instanceof Nfile) {
                Nfile file = (Nfile) value;
                if (file.isFile()) {
                    entity.addPart(key, new FileBody(file.getFile(), file.getName()));
                } else {
                    entity.addPart(key, new ByteArrayBody(file.getBytes(), file.getName()));
                }
            } else if (value instanceof Collection || value instanceof Object[]) {
                Collection collection = value instanceof Collection ? (Collection) value
                    : Arrays.asList((Object[]) value);
                for (Object object : collection) {
                    if (object instanceof File) {
                        entity.addPart(key, new FileBody((File) object));
                    } else if (object instanceof Nfile) {
                        Nfile file = (Nfile) object;
                        if (file.isFile()) {
                            entity.addPart(key, new FileBody(file.getFile(), file.getName()));
                        } else {
                            entity.addPart(key, new ByteArrayBody(file.getBytes(), file.getName()));
                        }
                    } else {
                        entity.addPart(key, new StringBody(Strings.toString(object), charset));
                    }
                }
            } else {
                entity.addPart(key, new StringBody(Strings.toString(value), charset));
            }
        }
        return entity;
    }

    /**
     * 获取Http资源请求对象
     *
     * @param url    请求地址
     * @param method 请求方式
     * @return Http资源请求对象
     * @throws IOException IO操作异常
     */
    public static HttpUriRequest getHttpUriRequest(String url, Method method) throws IOException {
        return getHttpUriRequest(url, method, Collections.emptyMap());
    }

    /**
     * 获取Http资源请求对象
     *
     * @param url        请求地址
     * @param method     请求方式
     * @param parameters 请求参数
     * @return Http资源请求对象
     * @throws IOException IO操作异常
     */
    public static HttpUriRequest getHttpUriRequest(String url, Method method, Map parameters)
        throws IOException {
        if (url == null) {
            throw new IllegalArgumentException("Url must not be null");
        }
        if (method == null) {
            throw new IllegalArgumentException("Method must not be null");
        }
        if (method == Method.GET) {
            String entity = getGetEntity(parameters);
            if (entity == null) {
                return new HttpGet(url);
            }
            return new HttpGet(new StringBuilder(url).append('?').append(entity).toString());
        } else if (method == Method.DELETE) {
            String entity = getGetEntity(parameters);
            if (entity == null) {
                return new HttpDelete(url);
            }
            return new HttpDelete(new StringBuilder(url).append('?').append(entity).toString());
        } else if (method == Method.POST) {
            HttpPost httpPost = new HttpPost(url);
            httpPost.setEntity(getHttpEntity(parameters));
            return httpPost;
        } else if (method == Method.PUT) {
            HttpPut httpPut = new HttpPut(url);
            httpPut.setEntity(getHttpEntity(parameters));
            return httpPut;
        }
        throw new RuntimeException("Not support method:" + method);
    }

    /**
     * 获取Http请求数据字节流
     *
     * @param request Http请求对象
     * @return 字节数组
     * @throws IOException IO操作异常
     */
    public static byte[] getBytes(HttpServletRequest request) throws IOException {
        if (request == null) {
            throw new IllegalArgumentException("HttpServletRequest must not be null");
        }
        InputStream is = request.getInputStream();
        try {
            return Streams.getBytes(is);
        } finally {
            is.close();
        }
    }

    /**
     * 获取Http请求结果字节数组
     *
     * @param request Http请求对象
     * @return 字节数组
     * @throws IOException IO操作异常
     */
    public static byte[] getBytes(HttpUriRequest request) throws IOException {
        return getBytes(getClient(), request);
    }

    /**
     * 获取Http请求结果字节数组
     *
     * @param client  Http客户端对象
     * @param request Http请求对象
     * @return 字节数组
     * @throws IOException IO操作异常
     */
    public static byte[] getBytes(HttpClient client, HttpUriRequest request) throws IOException {
        if (client == null) {
            throw new IllegalArgumentException("HttpClient must not be null");
        }
        if (request == null) {
            throw new IllegalArgumentException("HttpServletRequest must not be null");
        }
        if (request.getURI().getScheme().equalsIgnoreCase(Protocol.https.toString())) {
            bindSSL(client);
        }
        HttpEntity entity = client.execute(request).getEntity();
        try {
            return EntityUtils.toByteArray(entity);
        } finally {
            EntityUtils.consumeQuietly(entity);
        }
    }

    /**
     * 获取Http请求结果字节数组
     *
     * @param url    请求地址
     * @param method 请求方式
     * @return 字节数组
     * @throws IOException IO操作异常
     */
    public static byte[] getBytes(String url, Method method) throws IOException {
        return getBytes(getClient(), url, method);
    }

    /**
     * 获取Http请求结果字节数组
     *
     * @param client Http客户端对象
     * @param url    请求地址
     * @param method 请求方式
     * @return 字节数组
     * @throws IOException IO操作异常
     */
    public static byte[] getBytes(HttpClient client, String url, Method method) throws IOException {
        return getBytes(client, url, method, Collections.emptyMap());
    }

    /**
     * 获取Http请求结果字节数组
     *
     * @param url        请求地址
     * @param method     请求方式
     * @param parameters 请求参数
     * @return 字节数组
     * @throws IOException IO操作异常
     */
    public static byte[] getBytes(String url, Method method, Map parameters) throws IOException {
        return getBytes(getClient(), url, method, parameters);
    }

    /**
     * 获取Http请求结果字节数组
     *
     * @param client     Http客户端对象
     * @param url        请求地址
     * @param method     请求方式
     * @param parameters 请求参数
     * @return 字节数组
     * @throws IOException IO操作异常
     */
    public static byte[] getBytes(HttpClient client, String url, Method method, Map parameters)
        throws IOException {
        return getBytes(client, getHttpUriRequest(url, method, parameters));
    }

    /**
     * 获取Http请求数据流字符串形式
     *
     * @param request Http请求对象
     * @return 数据字符串
     * @throws IOException IO操作异常
     */
    public static String getString(HttpServletRequest request) throws IOException {
        return new String(getBytes(request));
    }

    /**
     * 获取Http请求结果字符串
     *
     * @param request Http请求对象
     * @return 字符串
     * @throws IOException IO操作异常
     */
    public static String getString(HttpUriRequest request) throws IOException {
        return getString(getClient(), request);
    }

    /**
     * 获取Http请求结果字符串
     *
     * @param client  Http客户端对象
     * @param request Http请求对象
     * @return 字符串
     * @throws IOException IO操作异常
     */
    public static String getString(HttpClient client, HttpUriRequest request) throws IOException {
        if (client == null) {
            throw new IllegalArgumentException("HttpClient must not be null");
        }
        if (request == null) {
            throw new IllegalArgumentException("HttpUriRequest must not be null");
        }
        if (request.getURI().getScheme().equalsIgnoreCase(Protocol.https.toString())) {
            bindSSL(client);
        }
        HttpEntity entity = client.execute(request).getEntity();
        try {
            return EntityUtils.toString(entity, Strings.UTF8);
        } finally {
            EntityUtils.consumeQuietly(entity);
        }
    }

    /**
     * 获取Http请求结果字符串
     *
     * @param url    请求地址
     * @param method 请求方式
     * @return 字符串
     * @throws IOException IO操作异常
     */
    public static String getString(String url, Method method) throws IOException {
        return getString(getClient(), url, method);
    }

    /**
     * 获取Http请求结果字符串
     *
     * @param client Http客户端对象
     * @param url    请求地址
     * @param method 请求方式
     * @return 字符串
     * @throws IOException IO操作异常
     */
    public static String getString(HttpClient client, String url, Method method) throws IOException {
        return getString(client, url, method, Collections.emptyMap());
    }

    /**
     * 获取Http请求结果字符串
     *
     * @param url        请求地址
     * @param method     请求方式
     * @param parameters 请求参数
     * @return 字符串
     * @throws IOException IO操作异常
     */
    public static String getString(String url, Method method, Map parameters) throws IOException {
        return getString(getClient(), url, method, parameters);
    }

    /**
     * 获取Http请求结果字符串
     *
     * @param client     Http客户端对象
     * @param url        请求地址
     * @param method     请求方式
     * @param parameters 请求参数
     * @return 字符串
     * @throws IOException IO操作异常
     */
    public static String getString(HttpClient client, String url, Method method, Map parameters)
        throws IOException {
        return getString(client, getHttpUriRequest(url, method, parameters));
    }

    /**
     * 获取Http请求结果输入流
     *
     * @param request Http请求对象
     * @return 数据输入流
     * @throws IOException IO操作异常
     */
    public static InputStream getStream(HttpUriRequest request) throws IOException {
        return getStream(getClient(), request);
    }

    /**
     * 获取Http请求结果输入流
     *
     * @param client  Http客户端对象
     * @param request Http请求对象
     * @return 数据输入流
     * @throws IOException IO操作异常
     */
    public static InputStream getStream(HttpClient client, HttpUriRequest request) throws IOException {
        if (client == null) {
            throw new IllegalArgumentException("HttpClient must not be null");
        }
        if (request == null) {
            throw new IllegalArgumentException("HttpServletRequest must not be null");
        }
        if (request.getURI().getScheme().equalsIgnoreCase(Protocol.https.toString())) {
            bindSSL(client);
        }
        return client.execute(request).getEntity().getContent();
    }

    /**
     * 获取Http请求结果输入流
     *
     * @param url    请求地址
     * @param method 请求方式
     * @return 数据输入流
     * @throws IOException IO操作异常
     */
    public static InputStream getStream(String url, Method method) throws IOException {
        return getStream(getClient(), url, method);
    }

    /**
     * 获取Http请求结果输入流
     *
     * @param client Http客户端对象
     * @param url    请求地址
     * @param method 请求方式
     * @return 数据输入流
     * @throws IOException IO操作异常
     */
    public static InputStream getStream(HttpClient client, String url, Method method) throws IOException {
        return getStream(client, url, method, Collections.emptyMap());
    }

    /**
     * 获取Http请求结果输入流
     *
     * @param url        请求地址
     * @param method     请求方式
     * @param parameters 请求参数
     * @return 数据输入流
     * @throws IOException IO操作异常
     */
    public static InputStream getStream(String url, Method method, Map parameters) throws IOException {
        return getStream(getClient(), url, method, parameters);
    }

    /**
     * 获取Http请求结果输入流
     *
     * @param client     Http客户端对象
     * @param url        请求地址
     * @param method     请求方式
     * @param parameters 请求参数
     * @return 数据输入流
     * @throws IOException IO操作异常
     */
    public static InputStream getStream(HttpClient client, String url, Method method, Map parameters)
        throws IOException {
        return getStream(client, getHttpUriRequest(url, method, parameters));
    }

    /**
     * 视图渲染
     *
     * @param request  HTTP请求对象
     * @param response HTTP响应对象
     * @param template 视图模板名称
     * @throws IOException      IO操作异常
     * @throws ServletException Servlet操作异常
     */
    public static void render(HttpServletRequest request, HttpServletResponse response, String template)
        throws IOException, ServletException {
        render(request, response, template, Collections.emptyMap());
    }

    /**
     * 视图渲染
     *
     * @param request  HTTP请求对象
     * @param response HTTP响应对象
     * @param template 视图模板名称
     * @param context  渲染上下文数据
     * @throws IOException      IO操作异常
     * @throws ServletException Servlet操作异常
     */
    public static void render(HttpServletRequest request, HttpServletResponse response, String template,
                              Map context) throws IOException, ServletException {
        if (request == null) {
            throw new IllegalArgumentException("HttpServletRequest must not be null");
        }
        if (response == null) {
            throw new IllegalArgumentException("HttpServletResponse must not be null");
        }
        OutputStream os = response.getOutputStream();
        try {
            render(request, response, template, context, os);
        } finally {
            os.close();
        }
    }

    /**
     * 视图渲染
     *
     * @param request  HTTP请求对象
     * @param response HTTP响应对象
     * @param template 视图模板名称
     * @param output   数据输出流
     * @throws IOException      IO操作异常
     * @throws ServletException Servlet操作异常
     */
    public static void render(HttpServletRequest request, HttpServletResponse response, String template,
                              OutputStream output) throws IOException, ServletException {
        render(request, response, template, Collections.emptyMap(), output);
    }

    /**
     * 视图渲染
     *
     * @param request  HTTP请求对象
     * @param response HTTP响应对象
     * @param template 视图模板名称
     * @param context  渲染上下文数据
     * @param output   数据输出流
     * @throws IOException      IO操作异常
     * @throws ServletException Servlet操作异常
     */
    public static void render(HttpServletRequest request, HttpServletResponse response, String template,
                              Map context, OutputStream output) throws IOException, ServletException {
        if (request == null) {
            throw new IllegalArgumentException("HttpServletRequest must not be null");
        }
        if (response == null) {
            throw new IllegalArgumentException("HttpServletResponse must not be null");
        }
        if (template == null) {
            throw new IllegalArgumentException("Template must not be null");
        }
        if (context == null) {
            throw new IllegalArgumentException("Context must not be null");
        }
        if (output == null) {
            throw new IllegalArgumentException("OutputStream must not be null");
        }
        template = Strings.replace(Strings.replace(template, "\\", "/"), "//", "/");
        if (template.charAt(0) != '/') {
            template = new StringBuilder("/").append(template).toString();
        }
        if (!new File(ROOT_PATH, template).exists()) {
            throw new IOException("Template does not exist:" + template);
        }
        RequestDispatcher dispatcher = request.getRequestDispatcher(template);
        final PrintWriter writer = new PrintWriter(new OutputStreamWriter(output));
        for (Entry entry : context.entrySet()) {
            request.setAttribute(entry.getKey(), entry.getValue());
        }
        dispatcher.include(request, new HttpServletResponseWrapper(response) {

            @Override
            public PrintWriter getWriter() throws IOException {
                return writer;
            }

        });
        writer.flush();
    }

    /**
     * 获取视图内容
     *
     * @param request  HTTP请求对象
     * @param response HTTP响应对象
     * @param template 视图模板名称
     * @return 视图内容
     * @throws IOException      IO操作异常
     * @throws ServletException Servlet操作异常
     */
    public static String view(HttpServletRequest request, HttpServletResponse response, String template)
        throws IOException, ServletException {
        return view(request, response, template, Collections.emptyMap());
    }

    /**
     * 获取视图内容
     *
     * @param request  HTTP请求对象
     * @param response HTTP响应对象
     * @param template 视图模板名称
     * @param context  渲染上下文数据
     * @return 视图内容
     * @throws IOException      IO操作异常
     * @throws ServletException Servlet操作异常
     */
    public static String view(HttpServletRequest request, HttpServletResponse response, String template,
                              Map context) throws IOException, ServletException {
        OutputStream os = new ByteArrayOutputStream();
        try {
            render(request, response, template, context, os);
        } finally {
            os.close();
        }
        return os.toString();
    }

    /**
     * 请求转发
     *
     * @param request  HTTP请求对象
     * @param response HTTP响应对象
     * @param path     转发路径
     * @throws IOException      IO操作异常
     * @throws ServletException Servlet操作异常
     */
    public static void forward(HttpServletRequest request, HttpServletResponse response, String path)
        throws IOException, ServletException {
        if (request == null) {
            throw new IllegalArgumentException("HttpServletRequest must not be null");
        }
        if (response == null) {
            throw new IllegalArgumentException("HttpServletResponse must not be null");
        }
        if (path == null) {
            throw new IllegalArgumentException("Path must not be null");
        }
        String context = request.getContextPath();
        if (context == null) {
            request.getRequestDispatcher(path).forward(request, response);
        } else {
            request.getRequestDispatcher(context + path).forward(request, response);
        }
    }

    /**
     * 请求重定向
     *
     * @param request  HTTP请求对象
     * @param response HTTP响应对象
     * @param path     重定向路径
     * @throws IOException      IO操作异常
     * @throws ServletException Servlet操作异常
     */
    public static void redirect(HttpServletRequest request, HttpServletResponse response, String path)
        throws IOException, ServletException {
        if (request == null) {
            throw new IllegalArgumentException("HttpServletRequest must not be null");
        }
        if (response == null) {
            throw new IllegalArgumentException("HttpServletResponse must not be null");
        }
        if (path == null) {
            throw new IllegalArgumentException("Path must not be null");
        }
        String context = request.getContextPath();
        if (context == null) {
            response.sendRedirect(path);
        } else {
            response.sendRedirect(context + path);
        }
    }

    /**
     * HTTP响应
     *
     * @param response HTTP响应对象
     * @param object   输出对象
     * @throws IOException IO操作异常
     */
    public static void response(HttpServletResponse response, Object object) throws IOException {
        if (response == null) {
            throw new IllegalArgumentException("HttpServletResponse must not be null");
        }
        if (object == null) {
            return;
        }
        OutputStream os = response.getOutputStream();
        try {
            if (object instanceof File || object instanceof Nfile) {
                Nfile file = object instanceof Nfile ? (Nfile) object : new Nfile((File) object);
                response.setContentType("application/octet-stream");
                response.setHeader("Content-Disposition",
                    "attachment; filename=" + new String(file.getName().getBytes(), "ISO-8859-1"));
                response.setHeader("Content-Length", String.valueOf(file.getSize()));
                InputStream is = file.getInputStream();
                try {
                    Streams.write(is, os);
                } finally {
                    is.close();
                }
            } else if (object instanceof byte[]) {
                os.write((byte[]) object);
            } else if (object instanceof InputStream) {
                InputStream is = (InputStream) object;
                try {
                    Streams.write(is, os);
                } finally {
                    is.close();
                }
            } else if (object instanceof ReadableByteChannel) {
                ReadableByteChannel channel = (ReadableByteChannel) object;
                try {
                    Streams.write(channel, os);
                } finally {
                    channel.close();
                }
            } else {
                os.write(Strings.toString(object).getBytes());
            }
        } finally {
            os.close();
        }
    }

    /**
     * 获取Html解析器
     *
     * @return Html解析器
     */
    private static ParserDelegator getParserDelegator() {
        if (parserDelegator == null) {
            synchronized (Https.class) {
                if (parserDelegator == null) {
                    parserDelegator = new ParserDelegator();
                }
            }
        }
        return parserDelegator;
    }

    /**
     * 获取html中纯文本
     *
     * @param html html文本
     * @return 纯文本
     */
    public static String getText(String html) {
        try {
            return Strings.isEmpty(html) ? html : getText(new StringReader(html));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取html中纯文本
     *
     * @param reader html数据流
     * @return 纯文本
     * @throws IOException IO操作异常
     */
    public static String getText(Reader reader) throws IOException {
        if (reader == null) {
            throw new IllegalArgumentException("Reader must not be null");
        }
        final StringBuilder text = new StringBuilder();
        getParserDelegator().parse(reader, new ParserCallback() {

            @Override
            public void handleText(char[] data, int pos) {
                text.append(data);
            }

        }, true);
        return text.toString();
    }

    /**
     * 获取安全的Html(过滤掉script标签后的html内容)
     *
     * @param html Html内容
     * @return Html内容
     */
    public static String getSafeHtml(String html) {
        return Strings.isEmpty(html) ? html : SCRIPT_PATTERN.matcher(html).replaceAll(Strings.EMPTY_STRING);
    }

    /**
     * 销毁Http调用资源
     */
    public static void destroy() {
        if (manager != null) {
            synchronized (Https.class) {
                if (manager != null) {
                    logger.info("Destroy http client connection manager");
                    manager.shutdown();
                    manager = null;
                }
            }
        }
    }

}