package org.example.Utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import com.google.gson.Gson;
import com.google.gson.JsonObject;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.http.*;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.xml.bind.JAXBException;
import java.io.*;
import java.net.*;
import java.net.HttpCookie;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.zip.GZIPInputStream;
import java.util.regex.Pattern;

/**
 * ==============================================================================
 * 功能描述：WebUtil
 * 创 建 者：wzy
 * 创建日期：2017-01-19 11:01:32
 * ==============================================================================
 */
enum SendDataType {
    TEXT(0), JSON(1), XML(2), SCRIPT(3);

    private final int value;

    SendDataType(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }
}

enum InfoType {
    DEBUG(0), INFO(1), WARN(2), FAIL(3), ERROR(4);

    private final int value;

    InfoType(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }
}

class RequestParams {
    private static final Logger log = LoggerFactory.getLogger(RequestParams.class);

    private final String url;
    private String method;
    private CookieStore cookieStore;
    private boolean success;
    private String result;
    private Object sendData;
    private String strData;
    private SendDataType dataType = SendDataType.TEXT;
    private SendDataType resDataType = SendDataType.TEXT;
    private Action<String, InfoType> showInfo;
    private Action<InputStream, String> onSuccess;
    private Action<HttpURLConnection, String> beforeSend;
    private Runnable onStart;
    private Runnable onFail;
    private int timeout = 60000;
    private int readWriteTimeout = 60000;
    private int timeOutCount = 0;
    private String contentType;
    private String userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0";
    private String cookieInfo;
    private Map<String, String> header;
    private String encoding;
    private boolean allowAutoRedirect = false;
    private boolean keepAlive = true;
    private String referer;

    public RequestParams(String url) {
        this.url = url;
    }

    public String getUrl() {
        return url;
    }

    public String getMethod() {
        if (method == null || method.isEmpty()) {
            switch (dataType) {
                default:
                    method = "GET";
                    break;
                case XML:
                    method = "POST";
                    break;
            }
        }
        return method;
    }

    public void setMethod(String method) {
        this.method = method;
    }

    public CookieStore getCookieStore() {
        return cookieStore;
    }

    public void setCookieStore(CookieStore cookieStore) {
        this.cookieStore = cookieStore;
    }

    public boolean isSuccess() {
        return success;
    }

    public void setSuccess(boolean success) {
        this.success = success;
    }

    public String getResult() {
        return result;
    }

    public void setResult(String result) {
        this.result = result;
    }

    public JsonObject getJResult() {
        if (result != null && !result.isEmpty() && (result.startsWith("{") || dataType == SendDataType.JSON)) {
            try {
                return new Gson().fromJson(result, JsonObject.class);
            } catch (Exception e) {
                return null;
            }
        }
        return null;
    }

    public <T> T getCusResult(Class<T> clazz) {
        if (dataType == SendDataType.JSON && result != null && !result.isEmpty()) {
            return new Gson().fromJson(result, clazz);
        }
        return null;
    }

    public Object getSendData() throws JAXBException, IOException {
        if (sendData != null && (sendData instanceof byte[] || sendData instanceof InputStream)) {
            return sendData;
        }
        return getSendStr(sendData);
    }

    public void setSendData(Object sendData) {
        this.sendData = sendData;
    }

    public String getStrData() {
        try {
            return URLEncoder.encode(strData, StandardCharsets.UTF_8.name());
        } catch (UnsupportedEncodingException e) {
            return strData;
        }
    }

    public void setStrData(String strData) {
        this.strData = strData;
    }

    public SendDataType getDataType() {
        return dataType;
    }

    public void setDataType(SendDataType dataType) {
        this.dataType = dataType;
    }

    public SendDataType getResDataType() {
        return resDataType;
    }

    public void setResDataType(SendDataType resDataType) {
        this.resDataType = resDataType;
    }

    public Action<String, InfoType> getShowInfo() {
        return showInfo;
    }

    public void setShowInfo(Action<String, InfoType> showInfo) {
        this.showInfo = showInfo;
    }

    public Action<InputStream, String> getOnSuccess() {
        return onSuccess;
    }

    public void setOnSuccess(Action<InputStream, String> onSuccess) {
        this.onSuccess = onSuccess;
    }

    public Action<HttpURLConnection, String> getBeforeSend() {
        return beforeSend;
    }

    public void setBeforeSend(Action<HttpURLConnection, String> beforeSend) {
        this.beforeSend = beforeSend;
    }

    public Runnable getOnStart() {
        return onStart;
    }

    public void setOnStart(Runnable onStart) {
        this.onStart = onStart;
    }

    public Runnable getOnFail() {
        return onFail;
    }

    public void setOnFail(Runnable onFail) {
        this.onFail = onFail;
    }

    public int getTimeout() {
        return timeout;
    }

    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    public int getReadWriteTimeout() {
        return readWriteTimeout;
    }

    public void setReadWriteTimeout(int readWriteTimeout) {
        this.readWriteTimeout = readWriteTimeout;
    }

    public int getTimeOutCount() {
        return timeOutCount;
    }

    public void setTimeOutCount(int timeOutCount) {
        this.timeOutCount = timeOutCount;
    }

    public String getContentType() {
        if (contentType == null || contentType.isEmpty()) {
            switch (dataType) {
                default:
                    contentType = "application/x-www-form-urlencoded;charset=utf-8";
                    break;
                case XML:
                    contentType = "text/xml";
                    break;
                case JSON:
                    contentType = "application/json;charset=utf-8";
                    break;
            }
        }
        return contentType;
    }

    public void setContentType(String contentType) {
        this.contentType = contentType;
    }

    public String getUserAgent() {
        return userAgent;
    }

    public void setUserAgent(String userAgent) {
        this.userAgent = userAgent;
    }

    public String getCookieInfo() {
        return cookieInfo;
    }

    public void setCookieInfo(String cookieInfo) {
        this.cookieInfo = cookieInfo;
        try {
            String host = new URL(url).getHost();
            if (cookieStore == null) {
                cookieStore = new CookieManager().getCookieStore();
            }
            updateCookie(cookieInfo, host);
        } catch (MalformedURLException e) {
            log.error("Exception caught", e);
        }
    }

    public Map<String, String> getHeader() {
        return header;
    }

    public void setHeader(Map<String, String> header) {
        this.header = header;
    }

    public String getEncoding() {
        return encoding;
    }

    public void setEncoding(String encoding) {
        this.encoding = encoding;
    }

    public boolean isAllowAutoRedirect() {
        return allowAutoRedirect;
    }

    public void setAllowAutoRedirect(boolean allowAutoRedirect) {
        this.allowAutoRedirect = allowAutoRedirect;
    }

    public boolean isKeepAlive() {
        return keepAlive;
    }

    public void setKeepAlive(boolean keepAlive) {
        this.keepAlive = keepAlive;
    }

    public String getReferer() {
        return referer;
    }

    public void setReferer(String referer) {
        this.referer = referer;
    }

    public String getAccept() {
        switch (dataType) {
            default:
                return "text/html, */*; q=0.01";
            case TEXT:
                return "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
            case SCRIPT:
                return "/";
            case JSON:
                return "application/json, text/javascript, */*; q=0.01";
        }
    }

    public String getAuthority() {
        try {
            URL urlObj = new URL(url);
            return urlObj.getAuthority();
        } catch (MalformedURLException e) {
            return "";
        }
    }

    public String getHost() {
        try {
            URL urlObj = new URL(url);
            return urlObj.getHost();
        } catch (MalformedURLException e) {
            return "";
        }
    }

    public void showMsg(String msg, InfoType infoType) {
        if (showInfo != null) {
            showInfo.execute(msg, infoType);
        }
    }

    private String getSendStr(Object sendData) throws JAXBException, IOException {
        switch (dataType) {
            default:
                return toQueryStr(sendData);
            case XML:
                // 假设XmlUtil存在XML序列化方法
                return XmlUtil.xmlSerialize(sendData, StandardCharsets.UTF_8);
        }
    }

    private String toQueryStr(Object sendData) {
        if (sendData == null) {
            return "";
        }

        if (sendData instanceof String) {
            String sendDataStr = (String) sendData;
            return processQueryString(sendDataStr);
        } else if (sendData instanceof List<?>) {
            List<?> list = (List<?>) sendData;
            List<String> stringList = new ArrayList<>();
            for (Object obj : list) {
                stringList.add(obj.toString());
            }
            return String.join("&", stringList);
        } else if (sendData instanceof JsonObject || dataType == SendDataType.JSON) {
            return new Gson().toJson(sendData);
        } else if (sendData instanceof Map<?, ?>) {
            Map<?, ?> map = (Map<?, ?>) sendData;
            MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
            for (Map.Entry<?, ?> entry : map.entrySet()) {
                params.add(entry.getKey().toString(), entry.getValue().toString());
            }
            return buildQuery(params, "utf8", getMethod(), getContentType());
        }

        return "";
    }

    private String processQueryString(String query) {
        if (query.isEmpty()) {
            return "";
        }

        if (dataType == SendDataType.JSON || getContentType().toLowerCase().contains("application/json")) {
            return query;
        }

        List<String> paramList = new ArrayList<>();
        String[] keyValues = query.split("&");
        for (String keyVal : keyValues) {
            int eqIndex = keyVal.indexOf("=");
            if (eqIndex > -1) {
                String key = keyVal.substring(0, eqIndex);
                String value = keyVal.substring(eqIndex + 1).trim();
                try {
                    paramList.add(key + "=" + URLEncoder.encode(value, StandardCharsets.UTF_8.name()));
                } catch (UnsupportedEncodingException e) {
                    paramList.add(key + "=" + value);
                }
            } else {
                paramList.add(keyVal);
            }
        }
        paramList.add(String.valueOf(new Random().nextInt(900) + 100));
        return String.join("&", paramList);
    }

    public static String buildQuery(MultiValueMap<String, String> parameters, String encode, String method, String contentType) {
        if (parameters == null || parameters.isEmpty()) {
            return "";
        }

        List<String> params = new ArrayList<>();
        for (Map.Entry<String, List<String>> entry : parameters.entrySet()) {
            String name = entry.getKey();
            for (String value : entry.getValue()) {
                if (name != null && !name.isEmpty()) {
                    String encodedValue = value;
                    if (method.equalsIgnoreCase("get") ||
                            (method.equalsIgnoreCase("post") &&
                                    contentType.toLowerCase().contains("application/x-www-form-urlencoded"))) {
                        try {
                            if ("gb2312".equals(encode)) {
                                encodedValue = URLEncoder.encode(value, "GB2312");
                            } else if ("utf8".equals(encode)) {
                                encodedValue = URLEncoder.encode(value, StandardCharsets.UTF_8.name());
                            }
                        } catch (UnsupportedEncodingException e) {
                            // 编码失败使用原始值
                        }
                    }
                    params.add(name + "=" + encodedValue);
                }
            }
        }

        if (method.equalsIgnoreCase("get")) {
            params.add(String.valueOf(new Random().nextInt(900) + 100));
        }

        return String.join("&", params);
    }

    private void updateCookie(String cookieInfo, String host) {
        if (cookieInfo == null || cookieInfo.isEmpty() || host == null) {
            return;
        }

        String[] cookies = cookieInfo.split(";");
        for (String cookie : cookies) {
            cookie = cookie.trim();
            if (cookie.isEmpty()) {
                continue;
            }

            String[] parts = cookie.split("=", 2);
            if (parts.length < 2) {
                continue;
            }

            String name = parts[0].trim();
            String value = parts[1].trim();

            try {
                URL url = new URL("http", host, 80, "/");
                HttpCookie httpCookie = new HttpCookie(name, value);
                httpCookie.setDomain(host);
                httpCookie.setPath("/");
                cookieStore.add(url.toURI(), httpCookie);
            } catch (Exception e) {
                log.error("Exception caught", e);
            }
        }
    }
}

// 保留此定义（通用双参数接口）
@FunctionalInterface
interface Action<T, U> {
    void execute(T t, U u);
}

public class WebUtil {

    private static final Logger log = LoggerFactory.getLogger(WebUtil.class);
    private static final RestTemplate restTemplate = new RestTemplate();
    private static final Pattern IP_PATTERN = Pattern.compile("^((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)$");

    /**
     * 获取指定链接的网页内容
     */
    public static String getContentByUrl(String url) {
        HttpURLConnection connection = null;
        InputStream inputStream = null;
        BufferedReader reader = null;

        try {
            URL urlObj = new URL(url);
            connection = (HttpURLConnection) urlObj.openConnection();
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(5000);
            connection.setReadTimeout(5000);

            inputStream = connection.getInputStream();
            reader = new BufferedReader(new InputStreamReader(inputStream, "GBK"));

            StringBuilder content = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                content.append(line);
            }
            return content.toString();
        } catch (Exception e) {
            return "";
        } finally {
            closeResources(reader, inputStream, connection);
        }
    }

    /**
     * 发送HTTP请求（GET/POST）
     */
    public static String send(String url, Map<String, String> parameters, CookieStore cookieStore, boolean[] success, String method) {
        if (success == null || success.length == 0) {
            success = new boolean[1];
        }
        success[0] = false;
        cookieStore = cookieStore != null ? cookieStore : new CookieManager().getCookieStore();

        try {
            HttpHeaders headers = new HttpHeaders();
            headers.setAccept(Arrays.asList(MediaType.TEXT_HTML, MediaType.APPLICATION_XHTML_XML, MediaType.APPLICATION_XML, MediaType.ALL));
            headers.add("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2");
            headers.add("Accept-Encoding", "gzip, deflate");
            headers.add("Upgrade-Insecure-Request", "1");
            headers.add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; …) Gecko/20100101 Firefox/63.0");

            MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
            if (parameters != null) {
                parameters.forEach(params::add);
            }

            HttpEntity<MultiValueMap<String, String>> requestEntity;
            String requestUrl = url;

            if ("POST".equalsIgnoreCase(method)) {
                headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
                requestEntity = new HttpEntity<>(params, headers);
            } else {
                requestUrl = buildGetUrl(url, params);
                requestEntity = new HttpEntity<>(headers);
            }

            ResponseEntity<String> response = restTemplate.exchange(
                    requestUrl,
                    "POST".equalsIgnoreCase(method) ? HttpMethod.POST : HttpMethod.GET,
                    requestEntity,
                    String.class
            );

            success[0] = response.getStatusCode().is2xxSuccessful();
            return response.getBody() != null ? response.getBody() : "";
        } catch (RestClientException e) {
            return e.getMessage();
        }
    }

    /**
     * 使用RequestParams发送HTTP请求
     */
    public static String send(RequestParams pms) {
        if (pms == null) {
            return "无效参数";
        }

        if (pms.getOnStart() != null) {
            pms.getOnStart().run();
        }

        HttpURLConnection connection = null;
        InputStream inputStream = null;
        OutputStream outputStream = null;
        BufferedReader reader = null;

        try {
            String urlStr = pms.getUrl();
            String method = pms.getMethod().toUpperCase();
            boolean isPost = "POST".equals(method);

            // 处理GET请求参数
            if (!isPost && pms.getSendData() != null) {
                String query = pms.getSendData().toString();
                urlStr = buildGetUrl(urlStr, query);
            }

            URL url = new URL(urlStr);
            connection = (HttpURLConnection) url.openConnection();

            // 设置基础连接属性
            connection.setRequestMethod(method);
            connection.setConnectTimeout(pms.getTimeout());
            connection.setReadTimeout(pms.getReadWriteTimeout());
            connection.setInstanceFollowRedirects(pms.isAllowAutoRedirect());
            connection.setUseCaches(false);
            connection.setDoInput(true);

            // 设置请求头
            setRequestHeaders(connection, pms);

            // 处理POST请求数据
            if (isPost) {
                connection.setDoOutput(true);
                connection.setRequestProperty("Content-Type", pms.getContentType());

                // 处理100-Continue
                System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
                connection.setRequestProperty("Expect", "100-continue");

                Object sendData = pms.getSendData();
                if (sendData != null) {
                    byte[] postData;
                    if (sendData instanceof byte[]) {
                        postData = (byte[]) sendData;
                    } else if (sendData instanceof InputStream) {
                        try (InputStream is = (InputStream) sendData) {
                            postData = is.readAllBytes();
                        }
                    } else {
                        postData = sendData.toString().getBytes(StandardCharsets.UTF_8);
                    }

                    connection.setRequestProperty("Content-Length", String.valueOf(postData.length));
                    outputStream = connection.getOutputStream();
                    outputStream.write(postData);
                    outputStream.flush();
                }
            }

            // 执行前置回调
            if (pms.getBeforeSend() != null) {
                pms.getBeforeSend().execute(connection, "额外参数值");
            }

            // 获取响应
            int responseCode = connection.getResponseCode();
            inputStream = responseCode >= 400 ? connection.getErrorStream() : connection.getInputStream();

            // 处理gzip压缩
            String contentEncoding = connection.getContentEncoding();
            if (contentEncoding != null && contentEncoding.contains("gzip")) {
                inputStream = new GZIPInputStream(inputStream);
            }

            // 处理Cookie
            String setCookie = connection.getHeaderField("Set-Cookie");
            if (setCookie != null) {
                pms.setCookieInfo(setCookie);
            }

            // 处理响应数据
            String encoding = connection.getContentEncoding();
            if (encoding == null || encoding.isEmpty()) {
                encoding = "UTF-8";
            }

            reader = new BufferedReader(new InputStreamReader(inputStream, encoding));
            StringBuilder result = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                result.append(line);
            }

            // 执行成功回调
            if (pms.getOnSuccess() != null) {
                pms.getOnSuccess().execute(inputStream, "额外参数值");
            }

            pms.setSuccess(responseCode >= 200 && responseCode < 300);
            pms.setResult(result.toString());
            return pms.getResult();
        } catch (Exception e) {
            pms.setSuccess(false);
            pms.setResult(e.getMessage());
            pms.showMsg(e.getMessage(), InfoType.ERROR);
            return e.getMessage();
        } finally {
            closeResources(reader, inputStream, outputStream, connection);
            if (pms.getOnFail() != null && !pms.isSuccess()) {
                pms.getOnFail().run();
            }
        }
    }

    private static void setRequestHeaders(HttpURLConnection connection, RequestParams pms) {
        connection.setRequestProperty("Accept", pms.getAccept());
        connection.setRequestProperty("User-Agent", pms.getUserAgent());
        connection.setRequestProperty("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2");
        connection.setRequestProperty("Accept-Encoding", "gzip,deflate");
        connection.setRequestProperty("Upgrade-Insecure-Request", "1");

        if (pms.getHost() != null && !pms.getHost().isEmpty()) {
            connection.setRequestProperty("Host", pms.getHost());
        }

        if (pms.getReferer() != null && !pms.getReferer().isEmpty()) {
            connection.setRequestProperty("Referer", pms.getReferer());
        }

        if (pms.getHeader() != null && !pms.getHeader().isEmpty()) {
            pms.getHeader().forEach(connection::setRequestProperty);
        }

        // 处理Cookie
        if (pms.getCookieStore() != null) {
            try {
                URL url = new URL(pms.getUrl());
                List<HttpCookie> cookies = pms.getCookieStore().get(url.toURI());
                if (cookies != null && !cookies.isEmpty()) {
                    StringBuilder cookieStr = new StringBuilder();
                    for (HttpCookie cookie : cookies) {
                        if (cookieStr.length() > 0) {
                            cookieStr.append("; ");
                        }
                        cookieStr.append(cookie.getName()).append("=").append(cookie.getValue());
                    }
                    connection.setRequestProperty("Cookie", cookieStr.toString());
                }
            } catch (Exception e) {
                log.error("Exception caught", e);
            }
        }
    }

    private static String buildGetUrl(String baseUrl, String query) {
        if (query == null || query.isEmpty()) {
            return baseUrl;
        }
        return baseUrl.contains("?") ? baseUrl + "&" + query : baseUrl + "?" + query;
    }

    private static String buildGetUrl(String baseUrl, MultiValueMap<String, String> params) {
        if (params == null || params.isEmpty()) {
            return baseUrl;
        }
        return buildGetUrl(baseUrl, buildQuery(params, "utf8"));
    }

    private static String buildQuery(MultiValueMap<String, String> parameters, String encode) {
        if (parameters == null || parameters.isEmpty()) {
            return "";
        }

        StringBuilder query = new StringBuilder();
        boolean first = true;

        for (Map.Entry<String, List<String>> entry : parameters.entrySet()) {
            String name = entry.getKey();
            for (String value : entry.getValue()) {
                if (name == null || name.isEmpty()) {
                    continue;
                }

                if (!first) {
                    query.append("&");
                }
                first = false;

                try {
                    query.append(URLEncoder.encode(name, encode));
                    query.append("=");
                    if (value != null) {
                        query.append(URLEncoder.encode(value, encode));
                    }
                } catch (UnsupportedEncodingException e) {
                    query.append(name).append("=").append(value);
                }
            }
        }

        return query.toString();
    }

    /**
     * 获取服务器IP地址
     */
    public static String getServerIp() {
        try {
            String hostName = InetAddress.getLocalHost().getHostName();
            InetAddress[] addresses = InetAddress.getAllByName(hostName);

            StringBuilder ips = new StringBuilder();
            for (InetAddress addr : addresses) {
                if (ips.length() > 0) {
                    ips.append(",");
                }
                ips.append(addr.getHostAddress());
            }
            return ips.toString();
        } catch (UnknownHostException e) {
            return "";
        }
    }

    /**
     * 获取服务器公网IP
     */
    public static String getServerOutIp() {
        RequestParams pms = new RequestParams("https://www.ip.cn/api/index?ip=&type=0");
        pms.setDataType(SendDataType.JSON);
        send(pms);
        JsonObject result = pms.getJResult();
        return result != null && result.has("ip") ? result.get("ip").getAsString() : "";
    }

    /**
     * 获取客户端IP地址
     */
    public static String getIP() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        if (request == null) {
            return "";
        }

        try {
            String ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            if (ip != null && !ip.isEmpty()) {
                String[] ips = ip.split(",");
                if (ips.length > 0) {
                    ip = ips[0].trim();
                }
            }

            if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("REMOTE_ADDR");
            }

            if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }

            return isIP(ip) ? ip : "";
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * 检查IP地址格式
     */
    public static boolean isIP(String ip) {
        return ip != null && IP_PATTERN.matcher(ip).matches();
    }

    /**
     * 获取请求域名
     */
    public static String getRequestDomain() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        if (request == null) {
            return "";
        }
        String scheme = request.getScheme();
        String serverName = request.getServerName();
        int serverPort = request.getServerPort();

        String authority = serverName + (serverPort == 80 || serverPort == 443 ? "" : ":" + serverPort);
        return scheme + "://" + authority;
    }

    /**
     * 关闭资源工具方法
     */
    private static void closeResources(Closeable... resources) {
        for (Closeable resource : resources) {
            if (resource != null) {
                try {
                    resource.close();
                } catch (IOException e) {
                    // 忽略关闭异常
                }
            }
        }
    }

    private static void closeResources(BufferedReader reader, InputStream is, HttpURLConnection connection) {
        closeResources(reader, is);
        if (connection != null) {
            connection.disconnect();
        }
    }

    private static void closeResources(BufferedReader reader, InputStream is, OutputStream os, HttpURLConnection connection) {
        closeResources(reader, is, os);
        if (connection != null) {
            connection.disconnect();
        }
    }
}
