Merge pull request #587 from fengyukigo/main

feat: 上传 API 返回值新增 publicUrl 字段
This commit is contained in:
叁月柒
2026-06-12 18:42:38 +08:00
committed by GitHub
3 changed files with 51 additions and 56 deletions
+13
View File
@@ -3,6 +3,7 @@ import { createResponse, getUploadIp, getIPAddress, selectConsistentChannel, bui
import { retryFailedChunks, cleanupFailedMultipartUploads, checkChunkUploadStatuses, cleanupChunkData, cleanupUploadSession } from './chunkUpload';
import { S3Client, CompleteMultipartUploadCommand } from "@aws-sdk/client-s3";
import { getDatabase } from '../utils/databaseAdapter.js';
import { fetchPageConfig } from '../utils/sysConfig.js';
// 处理分块合并
export async function handleChunkMerge(context) {
@@ -112,6 +113,18 @@ async function startMerge(context, uploadId, totalChunks, originalFileName, orig
// 清理上传会话
await cleanupUploadSession(env, uploadId);
// 构建公开访问链接(使用 urlPrefix 配置)
if (result.result && result.result.length > 0) {
const src = result.result[0].src;
const fileName = src.startsWith('/file/') ? src.slice(6) : src.split('/file/').pop();
const pageConfig = await fetchPageConfig(env);
const urlPrefixConfig = pageConfig.config?.find(c => c.id === 'urlPrefix');
const urlPrefix = urlPrefixConfig?.value || '';
if (urlPrefix) {
result.result[0].publicUrl = `${urlPrefix.replace(/\/+$/, '')}/${fileName}`;
}
}
return createResponse(JSON.stringify(result.result), {
status: 200,
headers: { 'Content-Type': 'application/json' }
+11 -1
View File
@@ -4,6 +4,7 @@ import { TelegramAPI } from '../utils/storage/telegramAPI';
import { DiscordAPI } from '../utils/storage/discordAPI';
import { S3Client, CreateMultipartUploadCommand, UploadPartCommand, AbortMultipartUploadCommand } from "@aws-sdk/client-s3";
import { getDatabase, checkDatabaseConfig } from '../utils/databaseAdapter.js';
import { fetchPageConfig } from '../utils/sysConfig.js';
// 初始化分块上传
export async function initializeChunkedUpload(context) {
@@ -1271,8 +1272,17 @@ export async function uploadLargeFileToTelegram(context, file, fullId, metadata,
// 异步结束上传
waitUntil(endUpload(context, fullId, metadata));
// 构建公开访问链接(使用 urlPrefix 配置)
const pageConfig = await fetchPageConfig(env);
const urlPrefixConfig = pageConfig.config?.find(c => c.id === 'urlPrefix');
const urlPrefix = urlPrefixConfig?.value || '';
const responseBody = [{ 'src': returnLink }];
if (urlPrefix) {
responseBody[0].publicUrl = `${urlPrefix.replace(/\/+$/, '')}/${fullId}`;
}
return createResponse(
JSON.stringify([{ 'src': returnLink }]),
JSON.stringify(responseBody),
{
status: 200,
headers: {
+27 -55
View File
@@ -1,5 +1,5 @@
import { userAuthCheck, UnauthorizedResponse } from "../utils/auth/userAuth";
import { fetchUploadConfig, fetchSecurityConfig } from "../utils/sysConfig";
import { fetchUploadConfig, fetchSecurityConfig, fetchPageConfig } from "../utils/sysConfig";
import {
createResponse, getUploadIp, getIPAddress, resolveFileExt,
moderateContent, purgeCDNCache, isBlockedUploadIp, buildUniqueFileId, endUpload, getImageDimensions,
@@ -200,6 +200,12 @@ async function processFileUpload(context, formdata = null) {
returnLink = `/file/${fullId}`;
}
// 构建公开访问链接(使用 urlPrefix 配置)
const pageConfig = await fetchPageConfig(context.env);
const urlPrefixConfig = pageConfig.config?.find(c => c.id === 'urlPrefix');
const urlPrefix = urlPrefixConfig?.value || '';
context.publicUrl = urlPrefix ? `${urlPrefix.replace(/\/+$/, '')}/${fullId}` : '';
/* ====================================不同渠道上传======================================= */
// 出错是否切换渠道自动重试,默认开启
const autoRetry = url.searchParams.get('autoRetry') === 'false' ? false : true;
@@ -265,6 +271,19 @@ async function processFileUpload(context, formdata = null) {
return res;
}
// 构建上传成功响应,自动附带 publicUrl(如果已配置)
function buildUploadResponse(context, returnLink) {
const result = { src: returnLink };
if (context.publicUrl) {
result.publicUrl = context.publicUrl;
}
return createResponse(JSON.stringify([result]), {
headers: {
'Content-Type': 'application/json',
},
});
}
// 上传到Cloudflare R2
async function uploadFileToCloudflareR2(context, fullId, metadata, returnLink) {
const { env, waitUntil, uploadConfig, formdata, specifiedChannelName } = context;
@@ -317,15 +336,7 @@ async function uploadFileToCloudflareR2(context, fullId, metadata, returnLink) {
waitUntil(endUpload(context, fullId, metadata));
// 成功上传,将文件ID返回给客户端
return createResponse(
JSON.stringify([{ 'src': `${returnLink}` }]),
{
status: 200,
headers: {
'Content-Type': 'application/json',
}
}
);
return buildUploadResponse(context, returnLink);
}
@@ -417,12 +428,7 @@ async function uploadFileToS3(context, fullId, metadata, returnLink) {
// 结束上传
waitUntil(endUpload(context, fullId, metadata));
return createResponse(JSON.stringify([{ src: returnLink }]), {
status: 200,
headers: {
"Content-Type": "application/json",
},
});
return buildUploadResponse(context, returnLink);
} catch (error) {
return createResponse(`Error: Failed to upload to S3 - ${error.message}`, { status: 500 });
}
@@ -515,15 +521,7 @@ async function uploadFileToTelegram(context, fullId, metadata, fileExt, fileName
metadata.FileSize = (fileInfo.file_size / 1024 / 1024).toFixed(2);
// 将响应返回给客户端
res = createResponse(
JSON.stringify([{ 'src': `${returnLink}` }]),
{
status: 200,
headers: {
'Content-Type': 'application/json',
}
}
);
res = buildUploadResponse(context, returnLink);
// 图像审查(使用代理域名或官方域名)
@@ -583,15 +581,7 @@ async function uploadFileToExternal(context, fullId, metadata, returnLink) {
waitUntil(endUpload(context, fullId, metadata));
// 返回结果
return createResponse(
JSON.stringify([{ 'src': `${returnLink}` }]),
{
status: 200,
headers: {
'Content-Type': 'application/json',
}
}
);
return buildUploadResponse(context, returnLink);
}
@@ -671,13 +661,7 @@ async function uploadFileToDiscord(context, fullId, metadata, returnLink) {
waitUntil(endUpload(context, fullId, metadata));
// 返回成功响应
return createResponse(
JSON.stringify([{ 'src': returnLink }]),
{
status: 200,
headers: { 'Content-Type': 'application/json' }
}
);
return buildUploadResponse(context, returnLink);
} catch (error) {
console.error('Discord upload error:', error.message);
@@ -791,13 +775,7 @@ async function uploadFileToHuggingFace(context, fullId, metadata, returnLink) {
waitUntil(endUpload(context, fullId, metadata));
// 返回成功响应
return createResponse(
JSON.stringify([{ 'src': returnLink }]),
{
status: 200,
headers: { 'Content-Type': 'application/json' }
}
);
return buildUploadResponse(context, returnLink);
} catch (error) {
console.error('HuggingFace upload error:', error.message);
@@ -872,13 +850,7 @@ async function uploadFileToWebDAV(context, fullId, metadata, returnLink) {
waitUntil(endUpload(context, fullId, metadata));
return createResponse(
JSON.stringify([{ 'src': returnLink }]),
{
status: 200,
headers: { 'Content-Type': 'application/json' }
}
);
return buildUploadResponse(context, returnLink);
} catch (error) {
console.error('WebDAV upload error:', error.message);
return createResponse(`Error: WebDAV upload failed - ${error.message}`, { status: 500 });