From 93d4a0d506a7f2fe056a7a2c69dec8629feb825f Mon Sep 17 00:00:00 2001 From: sion123 <450702724@qq.com> Date: Mon, 2 Mar 2026 03:19:51 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/web-gold/src/composables/useUpload.js | 6 +-- frontend/config/api.js | 5 ++ .../file/service/TikUserFileServiceImpl.java | 54 ++++++++++++++++++- 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/frontend/app/web-gold/src/composables/useUpload.js b/frontend/app/web-gold/src/composables/useUpload.js index 8c9dc7bc67..320049e8b9 100644 --- a/frontend/app/web-gold/src/composables/useUpload.js +++ b/frontend/app/web-gold/src/composables/useUpload.js @@ -7,7 +7,7 @@ import { ref, reactive } from 'vue' import { message } from 'ant-design-vue' import { MaterialService } from '@/api/material' import { useUserStore } from '@/stores/user' -import { OSS_ORIGINAL, isDev } from '@gold/config/api' +import { OSS_ORIGINAL, OSS_DOMAIN, isDev } from '@gold/config/api' // GB转字节常量 const GB_TO_BYTES = 1073741824 @@ -109,10 +109,10 @@ export function useUpload() { // 发起PUT请求 // 开发环境:使用 /oss 代理避免CORS问题 - // 生产环境:直接使用OSS原始域名(需要OSS配置CORS) + // 生产环境:使用自定义域名(签名基于路径,域名可替换) const uploadUrl = isDev() ? presignedData.presignedUrl.replace(OSS_ORIGINAL, '/oss') - : presignedData.presignedUrl + : presignedData.presignedUrl.replace(OSS_ORIGINAL, OSS_DOMAIN) xhr.open('PUT', uploadUrl) if (presignedData.headers && presignedData.headers['Content-Type']) { xhr.setRequestHeader('Content-Type', presignedData.headers['Content-Type']) diff --git a/frontend/config/api.js b/frontend/config/api.js index e68cb530dd..da422682bb 100644 --- a/frontend/config/api.js +++ b/frontend/config/api.js @@ -43,6 +43,11 @@ export const API_BASE = { */ export const OSS_ORIGINAL = 'https://muye-ai-chat.oss-cn-hangzhou.aliyuncs.com' +/** + * OSS 自定义域名(生产环境使用) + */ +export const OSS_DOMAIN = 'https://oss.muyetools.cn' + /** * 判断是否为开发环境 */ diff --git a/yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/file/service/TikUserFileServiceImpl.java b/yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/file/service/TikUserFileServiceImpl.java index e457f8938a..147e1f2ee8 100644 --- a/yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/file/service/TikUserFileServiceImpl.java +++ b/yudao-module-tik/src/main/java/cn/iocoder/yudao/module/tik/file/service/TikUserFileServiceImpl.java @@ -13,6 +13,7 @@ import cn.iocoder.yudao.module.infra.api.file.FileApi; import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO; import cn.iocoder.yudao.module.infra.dal.mysql.file.FileMapper; import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClient; +import cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig; import cn.iocoder.yudao.module.infra.framework.file.core.utils.FileTypeUtils; import cn.iocoder.yudao.module.infra.service.file.FileConfigService; import cn.hutool.core.date.LocalDateTimeUtil; @@ -618,7 +619,14 @@ public class TikUserFileServiceImpl implements TikUserFileService { String presignedUrl = client.presignPutUrl(filePath); String visitUrl = client.presignGetUrl(filePath, null); - // 5. 构建返回结果 + // 5. 替换为自定义域名 + String domain = getFileClientDomain(client.getId()); + if (StrUtil.isNotBlank(domain)) { + presignedUrl = replaceUrlDomain(presignedUrl, domain); + visitUrl = replaceUrlDomain(visitUrl, domain); + } + + // 6. 构建返回结果 return Map.of( "presignedUrl", presignedUrl, "uploadUrl", HttpUtils.removeUrlQuery(visitUrl), @@ -631,6 +639,50 @@ public class TikUserFileServiceImpl implements TikUserFileService { ); } + /** + * 获取文件客户端的自定义域名 + * @param configId 配置编号 + * @return 自定义域名,如果没有配置则返回 null + */ + private String getFileClientDomain(Long configId) { + if (configId == null) { + return null; + } + try { + var fileConfig = fileConfigService.getFileConfig(configId); + if (fileConfig != null && fileConfig.getConfig() instanceof S3FileClientConfig s3Config) { + return s3Config.getDomain(); + } + } catch (Exception e) { + log.warn("[getFileClientDomain][获取文件配置失败,configId({})]", configId, e); + } + return null; + } + + /** + * 替换URL的域名部分 + * @param url 原始URL + * @param newDomain 新域名 + * @return 替换后的URL + */ + private String replaceUrlDomain(String url, String newDomain) { + if (StrUtil.isBlank(url) || StrUtil.isBlank(newDomain)) { + return url; + } + try { + // 提取原始URL的协议和主机名 + int schemeEnd = url.indexOf("://"); + if (schemeEnd > 0) { + int pathStart = url.indexOf("/", schemeEnd + 3); + String pathAndQuery = pathStart > 0 ? url.substring(pathStart) : ""; + return newDomain + pathAndQuery; + } + } catch (Exception e) { + log.warn("[replaceUrlDomain][替换域名失败,url({})]", url, e); + } + return url; + } + @Override @Transactional(rollbackFor = Exception.class) @SuppressWarnings("unchecked")