diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java index 10744d76bc..9de0377582 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java @@ -37,8 +37,10 @@ public class HttpUtils { } /** - * 解码 URL 参数 + * 解码 URL 参数(query parameter) + * 注意:此方法会将 + 解码为空格,适用于 query parameter,不适用于 URL path * + * @see #decodeUrlPath(String) * @param value 参数 * @return 解码后的参数 */ @@ -46,6 +48,20 @@ public class HttpUtils { return URLDecoder.decode(value, StandardCharsets.UTF_8); } + /** + * 解码 URL 路径 + * 与 {@link #decodeUtf8(String)} 不同,此方法不会将 + 解码为空格,保持 + 为字面字符 + * 适用于 URL path 部分的解码 + * + * @param path URL 路径 + * @return 解码后的路径 + */ + public static String decodeUrlPath(String path) { + // 先将 + 替换为 %2B,避免被 URLDecoder 解码为空格 + String encoded = path.replace("+", "%2B"); + return URLDecoder.decode(encoded, StandardCharsets.UTF_8); + } + @SuppressWarnings("unchecked") public static String replaceUrlQuery(String url, String key, String value) { UrlBuilder builder = UrlBuilder.of(url, Charset.defaultCharset()); diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java index 74a9361f99..dede821525 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java @@ -116,7 +116,7 @@ public class S3FileClient extends AbstractFileClient { public String presignGetUrl(String url, Integer expirationSeconds) { // 1. 将 url 转换为 path String path = StrUtil.removePrefix(url, config.getDomain() + "/"); - path = HttpUtils.decodeUtf8(HttpUtils.removeUrlQuery(path)); + path = HttpUtils.decodeUrlPath(HttpUtils.removeUrlQuery(path)); // 2.1 情况一:公开访问:无需签名 // 考虑到老版本的兼容,所以必须是 config.getEnablePublicAccess() 为 false 时,才进行签名