OSS 结果文件下载分流:新增 aiimage.oss.download-endpoint 配置,result/ 前缀对象生成独立下载域名直链(默认未配置时回退原行为)
Build Backend JAR / build (push) Has been cancelled

This commit is contained in:
2026-08-26 13:37:11 +08:00
parent 7b238522ed
commit 18db20099a
4 changed files with 67 additions and 3 deletions
@@ -9,6 +9,7 @@ public class OssProperties {
private String region; private String region;
private String endpoint; private String endpoint;
private String publicEndpoint; private String publicEndpoint;
private String downloadEndpoint;
private String bucket; private String bucket;
private String imageVideoBucket; private String imageVideoBucket;
private String digitalHumanBucket; private String digitalHumanBucket;
@@ -302,8 +302,12 @@ public class OssStorageService {
} }
public String generateFreshDownloadUrl(String value) { public String generateFreshDownloadUrl(String value) {
StorageLocation location = resolveStorageLocation(value);
if (location == null) {
return getPublicUrl(value); return getPublicUrl(value);
} }
return buildDownloadPublicUrl(location.objectKey(), location.bucket());
}
private void uploadFile(File file, String bucket, String objectKey) { private void uploadFile(File file, String bucket, String objectKey) {
if (file == null || !file.isFile()) { if (file == null || !file.isFile()) {
@@ -321,6 +325,22 @@ public class OssStorageService {
} }
private String getPublicUrl(String objectKey, String bucket) { private String getPublicUrl(String objectKey, String bucket) {
return buildPublicUrl(trimTrailingSlash(publicEndpoint()), objectKey, bucket);
}
/**
* 结果文件(objectKey 以 {@code result/} 开头)的下载直链。
* 配置了 download-endpoint 时走下载域名(独立出口/缓存节点),否则回退到公开 endpoint。
*/
private String buildDownloadPublicUrl(String objectKey, String bucket) {
String base = downloadEndpoint();
if (base == null || objectKey == null || !objectKey.startsWith("result/")) {
return getPublicUrl(objectKey, bucket);
}
return buildPublicUrl(base, objectKey, bucket);
}
private String buildPublicUrl(String baseUrl, String objectKey, String bucket) {
String encodedPath; String encodedPath;
try { try {
encodedPath = new URI(null, null, "/" + bucket + "/" + trimLeadingSlash(objectKey), null) encodedPath = new URI(null, null, "/" + bucket + "/" + trimLeadingSlash(objectKey), null)
@@ -328,7 +348,7 @@ public class OssStorageService {
} catch (Exception ex) { } catch (Exception ex) {
encodedPath = "/" + bucket + "/" + trimLeadingSlash(objectKey).replace(" ", "%20"); encodedPath = "/" + bucket + "/" + trimLeadingSlash(objectKey).replace(" ", "%20");
} }
return trimTrailingSlash(publicEndpoint()) + encodedPath; return trimTrailingSlash(baseUrl) + encodedPath;
} }
private StorageLocation resolveStorageLocation(String value) { private StorageLocation resolveStorageLocation(String value) {
@@ -488,6 +508,14 @@ public class OssStorageService {
return withScheme(firstNonBlank(ossProperties.getPublicEndpoint(), ossProperties.getEndpoint())); return withScheme(firstNonBlank(ossProperties.getPublicEndpoint(), ossProperties.getEndpoint()));
} }
private String downloadEndpoint() {
String configured = ossProperties.getDownloadEndpoint();
if (configured == null || configured.isBlank()) {
return null;
}
return withScheme(configured.trim());
}
private String resultObjectKey(File file, String moduleType) { private String resultObjectKey(File file, String moduleType) {
return String.format("result/%s/%s/%s", normalizeModuleType(moduleType), UUID.randomUUID(), file.getName()); return String.format("result/%s/%s/%s", normalizeModuleType(moduleType), UUID.randomUUID(), file.getName());
} }
@@ -97,6 +97,7 @@ aiimage:
region: ${AIIMAGE_OSS_REGION:us-east-1} region: ${AIIMAGE_OSS_REGION:us-east-1}
endpoint: ${AIIMAGE_OSS_ENDPOINT:https://oss.aishufu.top} endpoint: ${AIIMAGE_OSS_ENDPOINT:https://oss.aishufu.top}
public-endpoint: ${AIIMAGE_OSS_PUBLIC_ENDPOINT:https://oss.aishufu.top} public-endpoint: ${AIIMAGE_OSS_PUBLIC_ENDPOINT:https://oss.aishufu.top}
download-endpoint: ${AIIMAGE_OSS_DOWNLOAD_ENDPOINT:}
bucket: ${AIIMAGE_OSS_BUCKET:nanri-ai-images} bucket: ${AIIMAGE_OSS_BUCKET:nanri-ai-images}
image-video-bucket: ${AIIMAGE_IMAGE_VIDEO_OSS_BUCKET:shufu-video} image-video-bucket: ${AIIMAGE_IMAGE_VIDEO_OSS_BUCKET:shufu-video}
digital-human-bucket: ${AIIMAGE_DIGITAL_HUMAN_OSS_BUCKET:nanri-ai-digital-human} digital-human-bucket: ${AIIMAGE_DIGITAL_HUMAN_OSS_BUCKET:nanri-ai-digital-human}
@@ -12,10 +12,11 @@ import static org.junit.jupiter.api.Assertions.assertNull;
class OssStorageServiceTest { class OssStorageServiceTest {
private OssStorageService storageService; private OssStorageService storageService;
private OssProperties properties;
@BeforeEach @BeforeEach
void setUp() { void setUp() {
OssProperties properties = new OssProperties(); properties = new OssProperties();
properties.setEndpoint("https://oss.aishufu.top"); properties.setEndpoint("https://oss.aishufu.top");
properties.setPublicEndpoint("https://oss.aishufu.top"); properties.setPublicEndpoint("https://oss.aishufu.top");
properties.setBucket("nanri-ai-images"); properties.setBucket("nanri-ai-images");
@@ -93,4 +94,37 @@ class OssStorageServiceTest {
assertNull(storageService.normalizeManagedPublicUrl(null)); assertNull(storageService.normalizeManagedPublicUrl(null));
assertEquals(" ", storageService.normalizeManagedPublicUrl(" ")); assertEquals(" ", storageService.normalizeManagedPublicUrl(" "));
} }
@Test
void resultFilesUseDownloadEndpointWhenConfigured() {
properties().setDownloadEndpoint("https://download.aishufu.top");
assertEquals(
"https://download.aishufu.top/nanri-ai-images/result/similar_asin/1/%E9%87%8D%E6%96%B0-result.xlsx",
storageService.generateFreshDownloadUrl("result/similar_asin/1/重新-result.xlsx"));
assertEquals(
"https://download.aishufu.top/nanri-ai-images/result/similar_asin/1/re.xlsx",
storageService.generateFreshDownloadUrl("https://oss.aishufu.top/nanri-ai-images/result/similar_asin/1/re.xlsx"));
}
@Test
void nonResultAndUnmanagedValuesKeepPublicEndpoint() {
properties().setDownloadEndpoint("https://download.aishufu.top");
assertEquals(
"https://oss.aishufu.top/nanri-ai-images/supply_images/main.jpg",
storageService.generateFreshDownloadUrl("supply_images/main.jpg"));
assertEquals(
"https://download.aishufu.top/shufu-video/result/image_video/demo.mp4",
storageService.generateFreshDownloadUrl("shufu-video/result/image_video/demo.mp4"));
}
@Test
void downloadEndpointDisabledFallsBackToPublicEndpoint() {
assertEquals(
"https://oss.aishufu.top/nanri-ai-images/result/similar_asin/1/re.xlsx",
storageService.generateFreshDownloadUrl("result/similar_asin/1/re.xlsx"));
}
private OssProperties properties() {
return properties;
}
} }