fix(s3/storage): 恢复因合并异常丢失的S3 CDN代码,导致功能失效的问题

This commit is contained in:
Zhang Chao
2026-01-27 04:20:24 +00:00
parent 5d34052a1f
commit cdfd983f42
3 changed files with 74 additions and 1 deletions

View File

@@ -146,6 +146,7 @@ export async function getUploadConfig(db, env) {
bucketName: env.S3_BUCKET_NAME,
endpoint: env.S3_ENDPOINT,
pathStyle: env.S3_PATH_STYLE === 'true',
cdnDomain: env.S3_CDN_DOMAIN || '', // 可选的 CDN 域名
enabled: true,
fixed: true,
})
@@ -157,6 +158,7 @@ export async function getUploadConfig(db, env) {
if (s3Channels[0]) {
s3Channels[0].enabled = s.enabled
s3Channels[0].quota = s.quota // 保留容量限制配置
s3Channels[0].cdnDomain = s.cdnDomain // 保留 CDN 域名配置
}
continue

View File

@@ -630,6 +630,72 @@ async function handleR2File(context, fileId, encodedFileName, fileType) {
async function handleS3File(context, metadata, encodedFileName, fileType) {
const { Referer, url, request } = context;
// 检查是否配置了 CDN 文件完整路径
const cdnFileUrl = metadata?.S3CdnFileUrl;
// 如果配置了 CDN 文件路径,通过 CDN 读取文件
if (cdnFileUrl) {
try {
// 处理 HEAD 请求
if (request.method === 'HEAD') {
const headers = new Headers();
setCommonHeaders(headers, encodedFileName, fileType, Referer, url);
return handleHeadRequest(headers);
}
// 构建请求头
const fetchHeaders = {};
// 支持 Range 请求
const range = request.headers.get('Range');
if (range) {
fetchHeaders['Range'] = range;
}
// 通过 CDN 获取文件(直接使用完整路径,无需拼接)
const response = await fetch(cdnFileUrl, {
method: 'GET',
headers: fetchHeaders
});
if (!response.ok && response.status !== 206) {
// CDN 读取失败,回退到 S3 API
console.warn(`CDN fetch failed (${response.status}), falling back to S3 API`);
return await handleS3FileViaAPI(context, metadata, encodedFileName, fileType);
}
// 构建响应头
const headers = new Headers();
setCommonHeaders(headers, encodedFileName, fileType, Referer, url);
// 复制相关头部
if (response.headers.get('Content-Length')) {
headers.set('Content-Length', response.headers.get('Content-Length'));
}
if (response.headers.get('Content-Range')) {
headers.set('Content-Range', response.headers.get('Content-Range'));
}
return new Response(response.body, {
status: response.status,
headers
});
} catch (error) {
// CDN 读取出错,回退到 S3 API
console.error(`CDN fetch error: ${error.message}, falling back to S3 API`);
return await handleS3FileViaAPI(context, metadata, encodedFileName, fileType);
}
}
// 没有配置 CDN 文件路径,使用 S3 API
return await handleS3FileViaAPI(context, metadata, encodedFileName, fileType);
}
// 通过 S3 API 读取文件
async function handleS3FileViaAPI(context, metadata, encodedFileName, fileType) {
const { Referer, url, request } = context;
const s3Client = new S3Client({
region: metadata?.S3Region || "auto",
endpoint: metadata?.S3Endpoint,

View File

@@ -329,7 +329,7 @@ async function uploadFileToS3(context, fullId, metadata, returnLink) {
return createResponse('Error: No S3 channel provided', { status: 400 });
}
const { endpoint, pathStyle, accessKeyId, secretAccessKey, bucketName, region } = s3Channel;
const { endpoint, pathStyle, accessKeyId, secretAccessKey, bucketName, region, cdnDomain } = s3Channel;
// 创建 S3 客户端
const s3Client = new S3Client({
@@ -381,6 +381,11 @@ async function uploadFileToS3(context, fullId, metadata, returnLink) {
metadata.S3Region = region || "auto";
metadata.S3BucketName = bucketName;
metadata.S3FileKey = s3FileName;
// 保存 CDN 文件完整路径(如果配置了 CDN 域名)
if (cdnDomain) {
// 存储完整的 CDN 文件路径,而不是仅存储域名
metadata.S3CdnFileUrl = `${cdnDomain.replace(/\/$/, '')}/${s3FileName}`;
}
// 图像审查
if (uploadModerate && uploadModerate.enabled) {