Обновлен API для скачивания файлов: улучшена обработка ошибок, добавлена поддержка кодирования имен файлов для Unicode, изменены заголовки ответа для корректного скачивания. Логирование ошибок и успешных загрузок теперь более информативно.

This commit is contained in:
Bivekich
2025-07-17 13:12:15 +03:00
parent e191055682
commit 6a94d51032

View File

@ -1,64 +1,71 @@
import { NextRequest, NextResponse } from 'next/server' import { NextRequest, NextResponse } from 'next/server';
export async function GET(request: NextRequest) { export async function GET(request: NextRequest) {
try { try {
const searchParams = request.nextUrl.searchParams const searchParams = request.nextUrl.searchParams;
const fileUrl = searchParams.get('url') const fileUrl = searchParams.get('url');
const fileName = searchParams.get('filename') const fileName = searchParams.get('filename');
console.log('🔽 Проксируем скачивание файла:', fileUrl);
if (!fileUrl) { if (!fileUrl) {
return NextResponse.json( return NextResponse.json(
{ error: 'File URL is required' }, { error: 'URL файла не предоставлен' },
{ status: 400 } { status: 400 }
) );
} }
// Проверяем, что URL принадлежит нашему S3 хранилищу // Проверяем, что URL начинается с нашего доверенного домена
if (!fileUrl.includes('s3.twcstorage.ru/617774af-sfera/')) { if (!fileUrl.startsWith('https://s3.twcstorage.ru/')) {
return NextResponse.json( return NextResponse.json(
{ error: 'Invalid file URL' }, { error: 'Недопустимый URL файла' },
{ status: 400 } { status: 400 }
) );
} }
console.log('🔽 Проксируем скачивание файла:', fileUrl)
// Загружаем файл с S3 // Загружаем файл с S3
const response = await fetch(fileUrl, { const response = await fetch(fileUrl);
method: 'GET',
headers: {
'User-Agent': 'Mozilla/5.0 (compatible; SferaApp/1.0)',
}
})
if (!response.ok) { if (!response.ok) {
console.error('❌ Ошибка загрузки с S3:', response.status, response.statusText) console.error('❌ Ошибка загрузки файла с S3:', response.status, response.statusText);
return NextResponse.json( return NextResponse.json(
{ error: `Failed to fetch file: ${response.status}` }, { error: 'Файл не найден' },
{ status: response.status } { status: 404 }
) );
} }
// Получаем содержимое файла // Получаем буфер файла
const buffer = await response.arrayBuffer() const arrayBuffer = await response.arrayBuffer();
const buffer = new Uint8Array(arrayBuffer);
console.log('✅ Файл успешно загружен с S3, размер:', buffer.byteLength) console.log('✅ Файл успешно загружен с S3, размер:', buffer.length);
// Определяем MIME-тип из исходного ответа или устанавливаем по умолчанию
const contentType = response.headers.get('content-type') || 'application/octet-stream';
// Правильно кодируем имя файла для поддержки Unicode символов
let contentDisposition = 'attachment';
if (fileName) {
// Используем RFC 5987 кодирование для поддержки Unicode
const encodedFileName = encodeURIComponent(fileName);
contentDisposition = `attachment; filename*=UTF-8''${encodedFileName}`;
}
// Возвращаем файл с правильными заголовками для скачивания // Возвращаем файл с правильными заголовками для скачивания
return new NextResponse(buffer, { return new NextResponse(buffer, {
headers: { headers: {
'Content-Type': 'application/octet-stream', // Принудительное скачивание 'Content-Type': contentType,
'Content-Disposition': `attachment; filename="${fileName || 'file'}"`, 'Content-Disposition': contentDisposition,
'Content-Length': buffer.byteLength.toString(), 'Content-Length': buffer.length.toString(),
'Cache-Control': 'no-cache', 'Cache-Control': 'no-cache',
}, },
}) });
} catch (error) { } catch (error) {
console.error('❌ Ошибка в download-file API:', error) console.error('❌ Ошибка в download-file API:', error);
return NextResponse.json( return NextResponse.json(
{ error: 'Failed to download file' }, { error: 'Внутренняя ошибка сервера' },
{ status: 500 } { status: 500 }
) );
} }
} }