OSS 结果文件下载分流:新增 aiimage.oss.download-endpoint 配置,result/ 前缀对象生成独立下载域名直链(默认未配置时回退原行为)
Build Backend JAR / build (push) Has been cancelled
Build Backend JAR / build (push) Has been cancelled
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
+30
-2
@@ -302,7 +302,11 @@ public class OssStorageService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String generateFreshDownloadUrl(String value) {
|
public String generateFreshDownloadUrl(String value) {
|
||||||
return getPublicUrl(value);
|
StorageLocation location = resolveStorageLocation(value);
|
||||||
|
if (location == null) {
|
||||||
|
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) {
|
||||||
@@ -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}
|
||||||
|
|||||||
+35
-1
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user