2026-06-30 24681c81c09022f584a57006f2534b5f74723414
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java
@@ -9,6 +9,7 @@
import org.springframework.util.StringUtils;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
import org.springframework.web.util.UriUtils;
import java.net.URI;
import java.net.URLDecoder;
@@ -55,9 +56,59 @@
     * @return 解码后的路径
     */
    public static String decodeUrlPath(String path) {
        if (StrUtil.isEmpty(path)) {
            return path;
        }
        // 先将 + 替换为 %2B,避免被 URLDecoder 解码为空格
        String encoded = path.replace("+", "%2B");
        return URLDecoder.decode(encoded, StandardCharsets.UTF_8);
    }
    /**
     * 编码 URL 路径,按路径段编码,保留 / 分隔符
     *
     * @param path URL 路径,例如 20250602/xxx.pdf
     * @return 编码后的路径
     */
    public static String encodeUrlPath(String path) {
        if (StrUtil.isEmpty(path)) {
            return path;
        }
        String[] segments = path.split(StrUtil.SLASH, -1);
        StringBuilder result = new StringBuilder(path.length());
        for (int i = 0; i < segments.length; i++) {
            if (i > 0) {
                result.append(StrUtil.SLASH);
            }
            result.append(encodeUrlPathSegment(segments[i]));
        }
        return result.toString();
    }
    /**
     * 编码 URL 路径段
     *
     * @param segment URL 路径段
     * @return 编码后的路径段
     */
    public static String encodeUrlPathSegment(String segment) {
        return UriUtils.encodePathSegment(segment, StandardCharsets.UTF_8);
    }
    public static String removeUrlPathQueryAndFragment(String path) {
        if (StrUtil.isEmpty(path)) {
            return path;
        }
        int endIndex = path.length();
        int queryIndex = path.indexOf('?');
        if (queryIndex >= 0) {
            endIndex = queryIndex;
        }
        int fragmentIndex = path.indexOf('#');
        if (fragmentIndex >= 0 && fragmentIndex < endIndex) {
            endIndex = fragmentIndex;
        }
        return path.substring(0, endIndex);
    }
    public static String replaceUrlQuery(String url, String key, String value) {
@@ -200,4 +251,14 @@
        }
    }
    /**
     * WebSocket URL 切换成 HTTP URL:ws:// → http://;wss:// → https://;其它格式原样保留
     *
     * @param url 原始 URL
     * @return 切换协议后的 URL
     */
    public static String wsUrlToHttp(String url) {
        return StrUtil.startWithIgnoreCase(url, "ws") ? "http" + url.substring(2) : url;
    }
}