파일 업로드 시스템 만들기
파일 업로드 시스템 만들기 — 드래그 앤 드롭 파일 업로드와 CDN 연동을 바로 구현합니다.
드래그 앤 드롭 파일 업로드와 CDN 연동을 바로 구현합니다.
이 튜토리얼에서 배울 내용
파일 업로드 시스템 만들기
이미지, 문서, 동영상 같은 파일을 저장하려면 보통 AWS S3 같은 스토리지 서비스를 설정하고, 업로드 API를 만들어야 합니다. ConnectBase Storage를 사용하면 SDK 한 줄로 파일을 업로드하고, 자동으로 CDN URL을 받을 수 있습니다.
완성된 기능
- 파일 업로드 (드래그 앤 드롭)
- CDN URL 자동 생성 (업로드 즉시 접근 가능한 URL 반환)
- 파일 목록 조회
- 파일 삭제
사전 준비: 콘솔에서 스토리지 만들기
- ConnectBase 콘솔에 로그인합니다
- 왼쪽 메뉴에서 파일 스토리지를 클릭합니다
- 새 스토리지 버튼을 클릭합니다
- 이름을
my-storage로 입력합니다 - 접근 권한을 선택합니다:
- 공개: 누구나 URL로 파일에 접근 가능 (프로필 이미지, 상품 사진 등)
- 비공개: 인증된 사용자만 접근 가능 (내부 문서, 개인 파일 등)
1. 프로젝트 설정
npm create vite@latest upload-app -- --template react-ts
cd upload-app
npm install connectbase-client.env 파일을 만들고 Public Key를 입력합니다:
VITE_CONNECT_BASE_PUBLIC_KEY=cb_pk_여기에_퍼블릭키_입력
2. SDK 설정
src/lib/connectbase.ts:
import ConnectBase from 'connectbase-client'
export const cb = new ConnectBase({
publicKey: import.meta.env.VITE_CONNECT_BASE_PUBLIC_KEY
})3. 파일 업로드 훅 만들기
파일 업로드, 목록 조회, 삭제를 하나의 훅으로 묶어 관리합니다.
uploadFile() 을 호출하면 파일이 ConnectBase 스토리지에 저장되고 CDN URL 이 반환됩니다.
사전 준비: 콘솔 > 스토리지에서 새 스토리지를 생성하고 Storage ID 를 복사.
.env에VITE_STORAGE_ID=...로 저장.
src/hooks/useFileUpload.ts:
import { useState } from 'react'
import { cb } from '../lib/connectbase'
const STORAGE_ID = import.meta.env.VITE_STORAGE_ID as string
interface UploadedFile {
id: string // 파일 고유 ID (삭제할 때 사용)
name: string // 원본 파일 이름
url: string // CDN URL
size: number // 파일 크기 (바이트)
}
export function useFileUpload() {
const [files, setFiles] = useState<UploadedFile[]>([])
const [uploading, setUploading] = useState(false)
// 파일 업로드 — file 은 <input type="file"> 에서 받은 File 객체
// 경로 기반 (고정 URL — 같은 path 에 다시 업로드하면 URL 유지된 채로 파일 교체)
const upload = async (file: File, path?: string) => {
setUploading(true)
try {
const result = path
? await cb.storage.uploadByPath(STORAGE_ID, path, file)
: await cb.storage.uploadFile(STORAGE_ID, file)
setFiles(prev => [...prev, result as UploadedFile])
return result
} finally {
setUploading(false)
}
}
// 파일 목록 조회 (parentId 없으면 루트)
const listFiles = async (parentId?: string) => {
const result = await cb.storage.getFiles(STORAGE_ID, parentId)
setFiles(result as UploadedFile[])
}
// 파일 삭제
const removeFile = async (fileId: string) => {
await cb.storage.deleteFile(STORAGE_ID, fileId)
setFiles(prev => prev.filter(f => f.id !== fileId))
}
return { files, uploading, upload, listFiles, removeFile }
}
uploadFilevsuploadByPath:uploadFile은 UUID 기반 임의 URL 을 발급 (재업로드 시 URL 변경).uploadByPath는 경로 기반 고정 URL — 프로필 이미지처럼 URL 을 유지한 채 파일만 교체할 때 유용.
4. 드래그 앤 드롭 업로드 UI 만들기
파일을 드래그해서 놓으면 자동으로 업로드되는 UI를 만듭니다. 업로드된 파일은 목록으로 표시되며, 클릭하면 CDN URL로 열 수 있습니다.
src/components/FileUploader.tsx:
import { useFileUpload } from '../hooks/useFileUpload'
export function FileUploader() {
const { files, uploading, upload, removeFile } = useFileUpload()
// 파일을 드래그 앤 드롭했을 때 실행
const handleDrop = async (e: React.DragEvent) => {
e.preventDefault()
const droppedFiles = Array.from(e.dataTransfer.files)
for (const file of droppedFiles) {
// 두 번째 인자에 경로를 주면 uploadByPath (고정 URL), 생략하면 uploadFile (UUID URL)
await upload(file, `/images/${file.name}`)
}
}
return (
<div>
{/* 드롭존 — 여기에 파일을 드래그하세요 */}
<div
onDrop={handleDrop}
onDragOver={(e) => e.preventDefault()}
style={{ border: '2px dashed #ccc', padding: 40, textAlign: 'center' }}
>
{uploading ? '업로드 중...' : '파일을 드래그하거나 클릭하세요'}
</div>
{/* 업로드된 파일 목록 */}
<ul>
{files.map((f) => (
<li key={f.id}>
<a href={f.url} target="_blank" rel="noopener noreferrer">{f.name}</a>
<span> ({(f.size / 1024).toFixed(1)} KB)</span>
<button onClick={() => removeFile(f.id)}>삭제</button>
</li>
))}
</ul>
</div>
)
}5. 실행하기
npm run dev브라우저에서 http://localhost:5173 을 열고 파일을 드래그해보세요. 업로드된 파일의 CDN URL을 클릭하면 새 탭에서 파일이 열립니다.
다음 단계
- 이미지 미리보기 —
cb.storage.isImageFile(file)로 이미지 여부 판단 +<img src={f.url}> - 업로드 용량 제한 — 콘솔 > 스토리지 설정에서
max_file_size_mb조정 + 클라이언트에서 사전 체크 - 페이지 메타 설정 —
cb.storage.setPageMeta(storageId, { path, title, description })로 웹 스토리지 SEO/OG 태그 관리 - 경로 기반 조회 —
getByPath(storageId, '/avatars/user123.png')/getUrlByPath(storageId, path)(null 이면 미존재)
이 튜토리얼이 도움이 됐나요?