본문으로 건너뛰기

파일 업로드 시스템 만들기

파일 업로드 시스템 만들기드래그 앤 드롭 파일 업로드와 CDN 연동을 바로 구현합니다.

입문데이터16초읽기 약 3분업데이트 2026-04-14

드래그 앤 드롭 파일 업로드와 CDN 연동을 바로 구현합니다.

이 튜토리얼에서 배울 내용
콘솔에서 스토리지 생성
SDK로 파일 업로드
CDN URL 자동 생성
파일 목록 조회 및 삭제

파일 업로드 시스템 만들기

이미지, 문서, 동영상 같은 파일을 저장하려면 보통 AWS S3 같은 스토리지 서비스를 설정하고, 업로드 API를 만들어야 합니다. ConnectBase Storage를 사용하면 SDK 한 줄로 파일을 업로드하고, 자동으로 CDN URL을 받을 수 있습니다.

완성된 기능

  • 파일 업로드 (드래그 앤 드롭)
  • CDN URL 자동 생성 (업로드 즉시 접근 가능한 URL 반환)
  • 파일 목록 조회
  • 파일 삭제

사전 준비: 콘솔에서 스토리지 만들기

  1. ConnectBase 콘솔에 로그인합니다
  2. 왼쪽 메뉴에서 파일 스토리지를 클릭합니다
  3. 새 스토리지 버튼을 클릭합니다
  4. 이름을 my-storage로 입력합니다
  5. 접근 권한을 선택합니다:
    • 공개: 누구나 URL로 파일에 접근 가능 (프로필 이미지, 상품 사진 등)
    • 비공개: 인증된 사용자만 접근 가능 (내부 문서, 개인 파일 등)

1. 프로젝트 설정

bash
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:

typescript
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 를 복사. .envVITE_STORAGE_ID=... 로 저장.

src/hooks/useFileUpload.ts:

typescript
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 }
}

uploadFile vs uploadByPath: uploadFile 은 UUID 기반 임의 URL 을 발급 (재업로드 시 URL 변경). uploadByPath 는 경로 기반 고정 URL — 프로필 이미지처럼 URL 을 유지한 채 파일만 교체할 때 유용.

4. 드래그 앤 드롭 업로드 UI 만들기

파일을 드래그해서 놓으면 자동으로 업로드되는 UI를 만듭니다. 업로드된 파일은 목록으로 표시되며, 클릭하면 CDN URL로 열 수 있습니다.

src/components/FileUploader.tsx:

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. 실행하기

bash
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 이면 미존재)

이 튜토리얼이 도움이 됐나요?