fix: allow 500MB async knowledge uploads

This commit is contained in:
key
2026-07-29 17:55:12 +08:00
parent 6ba7df863f
commit 140aa6f31f
9 changed files with 42 additions and 37 deletions
@@ -1,6 +1,6 @@
--- # 临时文件存储位置 避免临时文件被系统清理报错
spring.servlet.multipart.location: /ruoyi/server/temp
# 资料处理异步队列支持视频和 ZIP 单文件至 500MB;具体接口仍按各自业务上限校验。
# 资料处理中心异步队列支持文档、图片、视频和 ZIP 单文件至 500MB;其他接口仍按各自业务上限校验。
spring.servlet.multipart.max-file-size: 500MB
spring.servlet.multipart.max-request-size: 520MB
@@ -56,10 +56,8 @@ public class AihrUploadQueueService {
private static final String TENANT_ID = "000000";
private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("MM-dd HH:mm:ss");
private static final long MAX_FILE_BYTES = 100L * 1024 * 1024;
/** 视频单独放宽:培训视频普遍大于文档;更大的走服务端目录导入。 */
private static final long MAX_VIDEO_BYTES = 500L * 1024 * 1024;
private static final long MAX_ARCHIVE_BYTES = 500L * 1024 * 1024;
/** 资料处理中心统一支持单文件 500 MiB;Spring multipart 请求上限需保持不低于该值。 */
private static final long MAX_FILE_BYTES = 500L * 1024 * 1024;
private static final long MAX_ARCHIVE_UNPACKED_BYTES = 2L * 1024 * 1024 * 1024;
private static final int MAX_ARCHIVE_ENTRIES = 1000;
private static final int MAX_ERROR_CHARS = 480;
@@ -125,14 +123,12 @@ public class AihrUploadQueueService {
if (!archive && !AihrSopSeedService.supportedFile(fileName)) {
throw new ServiceException("仅支持 txt/md/markdown/pdf/doc/docx/xls/xlsx/ppt/pptx/图片/视频/zip文件");
}
long maxBytes = archive ? MAX_ARCHIVE_BYTES
: AihrVideoService.videoFile(fileName) ? MAX_VIDEO_BYTES : MAX_FILE_BYTES;
if (file.getSize() > maxBytes) {
if (file.getSize() > MAX_FILE_BYTES) {
throw new ServiceException(archive
? "ZIP不能超过 500MB"
: AihrVideoService.videoFile(fileName)
? "视频不能超过 500MB,更大的请放到导入根目录走服务端导入"
: "文件不能超过 100MB");
: "文件不能超过 500MB");
}
ensureTable();
String batch = sanitizeBatchId(batchId);
@@ -494,7 +490,6 @@ public class AihrUploadQueueService {
if (!AihrSopSeedService.supportedFile(fileName)) {
continue;
}
long maxBytes = AihrVideoService.videoFile(fileName) ? MAX_VIDEO_BYTES : MAX_FILE_BYTES;
Path extracted = stagingPath(fileName);
long entryBytes = 0;
try (var output = Files.newOutputStream(extracted)) {
@@ -503,7 +498,7 @@ public class AihrUploadQueueService {
while ((read = zip.read(buffer)) != -1) {
entryBytes += read;
unpackedBytes += read;
if (entryBytes > maxBytes || unpackedBytes > MAX_ARCHIVE_UNPACKED_BYTES) {
if (entryBytes > MAX_FILE_BYTES || unpackedBytes > MAX_ARCHIVE_UNPACKED_BYTES) {
throw new ArchiveException("ZIP解压后文件超过大小限制");
}
output.write(buffer, 0, read);
@@ -735,12 +730,11 @@ public class AihrUploadQueueService {
|| object.getFileName() == null || object.getFileName().isBlank()) {
throw new ServiceException("MEDIA_RETRY_SOURCE_UNAVAILABLE: 原始文件不存在");
}
long maxBytes = AihrVideoService.videoFile(source.fileName()) ? MAX_VIDEO_BYTES : MAX_FILE_BYTES;
OssClient client = OssFactory.instance(object.getService());
Files.createDirectories(target.getParent());
try (InputStream input = client.getObjectContent(object.getFileName());
OutputStream output = Files.newOutputStream(target)) {
copyWithLimit(input, output, maxBytes);
copyWithLimit(input, output, MAX_FILE_BYTES);
} catch (RuntimeException | IOException e) {
deleteQuietly(target);
throw e;
@@ -8,6 +8,7 @@ import org.mockito.ArgumentCaptor;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
@@ -35,6 +36,14 @@ class AihrUploadQueueServiceTest {
@TempDir
Path tempDir;
@Test
void asyncQueueAllowsOrdinaryDocumentsUpTo500MiB() throws Exception {
Field field = AihrUploadQueueService.class.getDeclaredField("MAX_FILE_BYTES");
field.setAccessible(true);
assertEquals(500L * 1024 * 1024, field.getLong(null));
}
@Test
void expandsLegacyGbkZipAtomicallyAndKeepsDuplicateEntries() throws Exception {
Path staging = Files.createDirectories(tempDir.resolve("staging"));