diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/config/VoucherMinioConfig.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/config/VoucherMinioConfig.java
index 08ed5e38..5c0db187 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/config/VoucherMinioConfig.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/config/VoucherMinioConfig.java
@@ -5,19 +5,28 @@
package org.springblade.transport.config;
import io.minio.MinioClient;
+import lombok.extern.slf4j.Slf4j;
+import org.springblade.core.log.exception.ServiceException;
+import org.springblade.core.tool.utils.StringUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import java.net.URI;
+
/**
* 凭证图片 MinIO 客户端配置。
*
* 连接参数由 Nacos 的 file.storage.minio 配置提供。
+ *
+ * - {@code endpoint}:内网地址,供服务端 put/get,不能带 path
+ * - {@code transform-endpoint}:外网地址(可带 /oss),仅用于浏览器预签名
+ *
* 未配置 {@code file.storage.minio.endpoint} 时不注册该客户端,
- * 以免凭证上传功能缺失配置导致整个 blade-transport 服务无法启动;
- * 此时凭证相关接口会在调用时给出明确提示,而非启动即失败。
+ * 以免凭证上传功能缺失配置导致整个 blade-transport 服务无法启动。
*/
+@Slf4j
@Configuration
@ConditionalOnProperty(prefix = "file.storage.minio", name = "endpoint")
public class VoucherMinioConfig {
@@ -27,6 +36,30 @@ public class VoucherMinioConfig {
@Value("${file.storage.minio.endpoint:${minio.endpoint:}}") String endpoint,
@Value("${file.storage.minio.access-key-id:${minio.access-key:}}") String accessKey,
@Value("${file.storage.minio.access-key-secret:${minio.secret-key:}}") String secretKey) {
- return MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();
+ String clientEndpoint = resolveClientEndpoint(endpoint);
+ if (!clientEndpoint.equals(endpoint == null ? null : endpoint.trim())) {
+ log.warn("MinIO endpoint 含 path,已剥离为 {}(原值={})。服务端读写请配置内网 endpoint,外网请用 transform-endpoint",
+ clientEndpoint, endpoint);
+ }
+ return MinioClient.builder().endpoint(clientEndpoint).credentials(accessKey, secretKey).build();
+ }
+
+ /**
+ * MinIO SDK 不允许 endpoint 带 path(例如 https://host/oss)。
+ */
+ public static String resolveClientEndpoint(String endpoint) {
+ if (StringUtil.isBlank(endpoint)) {
+ throw new ServiceException("MinIO endpoint 不能为空");
+ }
+ URI uri = URI.create(endpoint.trim());
+ if (StringUtil.isBlank(uri.getScheme()) || StringUtil.isBlank(uri.getHost())) {
+ throw new ServiceException("MinIO endpoint 配置不正确: " + endpoint);
+ }
+ StringBuilder origin = new StringBuilder();
+ origin.append(uri.getScheme()).append("://").append(uri.getHost());
+ if (uri.getPort() > 0) {
+ origin.append(':').append(uri.getPort());
+ }
+ return origin.toString();
}
}
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/VoucherManageServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/VoucherManageServiceImpl.java
index 12e2c34e..16d35e08 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/VoucherManageServiceImpl.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/VoucherManageServiceImpl.java
@@ -88,6 +88,10 @@ public class VoucherManageServiceImpl extends BaseServiceImpl minioClientProvider;
private final String minioBucketName;
private final String minioRootDirectory;
+ private final String minioTransformEndpoint;
+ private final String minioAccessKey;
+ private final String minioSecretKey;
+ private volatile MinioClient transformPresignClient;
public VoucherManageServiceImpl(VoucherWaybillBatchMapper voucherWaybillBatchMapper, IProjectApplyService projectApplyService,
IWaybillService waybillService,
@@ -95,7 +99,10 @@ public class VoucherManageServiceImpl extends BaseServiceImpl minioClientProvider,
@Value("${file.storage.minio.bucket-name:${minio.bucket-name:}}") String minioBucketName,
- @Value("${file.storage.minio.root-directory:${minio.root-directory:}}") String minioRootDirectory) {
+ @Value("${file.storage.minio.root-directory:${minio.root-directory:}}") String minioRootDirectory,
+ @Value("${file.storage.minio.transform-endpoint:${minio.transform-endpoint:}}") String minioTransformEndpoint,
+ @Value("${file.storage.minio.access-key-id:${minio.access-key:}}") String minioAccessKey,
+ @Value("${file.storage.minio.access-key-secret:${minio.secret-key:}}") String minioSecretKey) {
this.voucherWaybillBatchMapper = voucherWaybillBatchMapper;
this.projectApplyService = projectApplyService;
this.waybillService = waybillService;
@@ -106,6 +113,9 @@ public class VoucherManageServiceImpl extends BaseServiceImpl 0) {
+ result.append(':').append(url.getPort());
+ }
+ result.append(pathPrefix).append(path);
+ if (Func.isNotEmpty(url.getRawQuery())) {
+ result.append('?').append(url.getRawQuery());
+ }
+ return result.toString();
+ }
+
+ private String normalizePathPrefix(String path) {
+ if (Func.isEmpty(path) || "/".equals(path)) {
+ return "";
+ }
+ String normalized = path.endsWith("/") ? path.substring(0, path.length() - 1) : path;
+ return normalized.startsWith("/") ? normalized : "/" + normalized;
+ }
+
private String normalizePlateNo(String plateNo) {
return plateNo == null ? null : plateNo.replaceAll("[\\s-]", "").toUpperCase();
}
diff --git a/doc/nacos/blade-prod.yaml b/doc/nacos/blade-prod.yaml
index 889576ad..4a8b3e3e 100644
--- a/doc/nacos/blade-prod.yaml
+++ b/doc/nacos/blade-prod.yaml
@@ -120,11 +120,13 @@ baidu:
request-timeout: 30s
token-refresh-advance: 1m
-# 凭证分片上传走 blade-file,与 /resource/oss 库表配置相互独立;外网地址必须在此配置并发布到 Nacos 后重启 blade-file
-# 不要使用可被空环境变量覆盖的 ${VAR:default},否则仍会签发 http://内网IP 预签名导致 Mixed Content
+# 对象存储(blade-file 分片上传 + blade-transport 凭证读写共用)
+# endpoint:内网地址,禁止带 path,供服务端 put/get(如 http://tms-prod-oss:9000 或 http://IP:19000)
+# transform-endpoint:外网 HTTPS,可带 /oss,仅用于浏览器预签名;切勿把该值填到 endpoint
file:
storage:
minio:
+ # endpoint: http://内网MinIO地址:端口
transform-endpoint: https://tms-prod.xinghy56.com/oss
powerjob: