Интеграция Uploadcare для загрузки файлов на сайт
Uploadcare — CDN с загрузкой файлов как сервис. Файл загружается напрямую с браузера на серверы Uploadcare, минуя ваш сервер. Бэкенд получает только UUID файла — ссылку на оригинал и все производные (ресайзы, конвертации, обрезки).
Основные возможности: загрузка из файловой системы, drag-and-drop, URL, Google Drive, Dropbox, камеры. Встроенный редактор изображений. Обработка изображений через URL-параметры без дополнительного кода.
Установка
npm install @uploadcare/react-uploader
# или vanilla JS виджет
npm install @uploadcare/file-uploader
Public key из дашборда Uploadcare — в переменные окружения:
VITE_UPLOADCARE_PUBLIC_KEY=демо
React-интеграция
import { FileUploaderRegular } from '@uploadcare/react-uploader'
import '@uploadcare/react-uploader/core.css'
interface UploadedFile {
uuid: string
cdnUrl: string
name: string
size: number
mimeType: string
}
interface UploaderProps {
onUpload: (file: UploadedFile) => void
accept?: string
maxFileSize?: number // байты
multiple?: boolean
}
function FileUploader({ onUpload, accept, maxFileSize, multiple = false }: UploaderProps) {
return (
<FileUploaderRegular
pubkey={import.meta.env.VITE_UPLOADCARE_PUBLIC_KEY}
multiple={multiple}
accept={accept}
maxLocalFileSizeBytes={maxFileSize}
onFileUploadSuccess={(file) => {
onUpload({
uuid: file.uuid,
cdnUrl: file.cdnUrl,
name: file.name ?? '',
size: file.size ?? 0,
mimeType: file.mimeType ?? '',
})
}}
onFileUploadFailed={(file) => {
console.error('Upload failed:', file.errors)
}}
imgOnly={accept === 'image/*'}
/>
)
}
Загрузка через API без виджета
Для кастомного UI — прямая загрузка через REST API:
interface UploadResult {
uuid: string
cdnUrl: string
}
async function uploadFile(
file: File,
publicKey: string,
onProgress?: (progress: number) => void
): Promise<UploadResult> {
const formData = new FormData()
formData.append('UPLOADCARE_PUB_KEY', publicKey)
formData.append('UPLOADCARE_STORE', '1')
formData.append('file', file)
const xhr = new XMLHttpRequest()
return new Promise((resolve, reject) => {
xhr.upload.addEventListener('progress', (e) => {
if (e.lengthComputable && onProgress) {
onProgress(Math.round((e.loaded / e.total) * 100))
}
})
xhr.addEventListener('load', () => {
if (xhr.status === 200) {
const data = JSON.parse(xhr.responseText)
resolve({
uuid: data.file,
cdnUrl: `https://ucarecdn.com/${data.file}/`,
})
} else {
reject(new Error(`Upload failed: ${xhr.statusText}`))
}
})
xhr.addEventListener('error', () => reject(new Error('Network error')))
xhr.open('POST', 'https://upload.uploadcare.com/base/')
xhr.send(formData)
})
}
Трансформации изображений через CDN URL
Это ключевая фишка Uploadcare — обработка через URL без дополнительного кода:
function buildImageUrl(uuid: string, transforms: string[]): string {
const ops = transforms.join('/-/')
return `https://ucarecdn.com/${uuid}/-/${ops}/`
}
// Примеры:
const thumbnail = buildImageUrl(uuid, ['scale_crop/300x300/center'])
const webp = buildImageUrl(uuid, ['format/webp', 'quality/smart'])
const resized = buildImageUrl(uuid, ['resize/800x/', 'format/webp'])
const blurred = buildImageUrl(uuid, ['blur/20'])
const grayscale = buildImageUrl(uuid, ['grayscale'])
// Progressive loading: сначала маленький, потом полный
const placeholder = buildImageUrl(uuid, ['scale_crop/20x20/center', 'blur/10'])
const full = buildImageUrl(uuid, ['resize/1200x/', 'format/webp', 'quality/smart'])
React-хук для загрузки с прогрессом
function useUploadcare(publicKey: string) {
const [progress, setProgress] = useState(0)
const [uploading, setUploading] = useState(false)
const [error, setError] = useState<string | null>(null)
const upload = useCallback(
async (file: File): Promise<UploadResult | null> => {
setUploading(true)
setProgress(0)
setError(null)
try {
const result = await uploadFile(file, publicKey, setProgress)
return result
} catch (e) {
setError(e instanceof Error ? e.message : 'Ошибка загрузки')
return null
} finally {
setUploading(false)
}
},
[publicKey]
)
return { upload, uploading, progress, error }
}
Валидация на бэкенде
Клиентская загрузка означает, что на бэкенд приходит только UUID. Нужно верифицировать, что файл реально существует и принадлежит вашему проекту:
// Laravel пример
public function store(Request $request): JsonResponse
{
$request->validate([
'file_uuid' => ['required', 'string', 'regex:/^[a-f0-9-]{36}$/'],
]);
$uuid = $request->input('file_uuid');
// Проверка через Uploadcare REST API
$response = Http::withHeaders([
'Authorization' => 'Uploadcare.Simple ' . config('services.uploadcare.public_key') . ':' . config('services.uploadcare.secret_key'),
])->get("https://api.uploadcare.com/files/{$uuid}/");
if (!$response->successful()) {
return response()->json(['error' => 'Файл не найден'], 422);
}
$fileInfo = $response->json();
// Проверка mime-типа
if (!str_starts_with($fileInfo['mime_type'], 'image/')) {
return response()->json(['error' => 'Допустимы только изображения'], 422);
}
// Сохраняем UUID в базу
$media = Media::create([
'uuid' => $uuid,
'cdn_url' => $fileInfo['original_file_url'],
'filename' => $fileInfo['original_filename'],
'size' => $fileInfo['size'],
'mime_type' => $fileInfo['mime_type'],
]);
return response()->json($media);
}
Что входит в работу
Подключение виджета или реализация кастомного UI загрузки, React-хук с прогрессом, хелперы для CDN-трансформаций, валидация UUID на бэкенде через Uploadcare API, настройка ограничений (типы файлов, размер).
Срок: 0.5–1 день.







