ReactNextCentral

서버 업로드 가이드

Published on
이 가이드는 Vercel Blob을 사용하여 서버 업로드를 수행하는 방법을 단계별로 설명합니다.
Table of Contents

Vercel Blob을 이용한 서버 업로드

Vercel Blob을 사용하여 서버 액션과 라우트 핸들러를 통해 파일을 업로드하는 방법을 배웁니다.

이 빠른 시작 가이드에서 다음을 수행하는 방법을 배웁니다.

  • Vercel 대시보드를 사용하여 프로젝트에 연결된 Blob 스토어를 생성하기
  • 서버에서 Blob SDK를 사용하여 파일 업로드하기

Vercel은 Vercel 함수에서 4.5MB의 요청 본문 크기 제한을 가지고 있습니다. 더 큰 파일을 업로드해야 한다면 클라이언트 업로드를 사용하세요.

Vercel Blob 사용 준비

Vercel Blob은 모든 프론트엔드 프레임워크와 호환됩니다. 먼저 패키지를 설치하세요.

npm install @vercel/blob

Blob 스토어 생성하기

Blob 스토어를 추가하고자 하는 프로젝트로 이동하세요. 스토리지 탭을 선택한 후 데이터베이스 연결 버튼을 클릭하세요.

새로 생성 탭에서 Blob을 선택하고 계속하기 버튼을 누릅니다.

"Images"라는 이름을 사용하고 새 Blob 스토어 생성을 선택하세요. 읽기-쓰기 토큰을 포함시키고자 하는 환경을 선택하세요. 고급 옵션에서 환경 변수의 접두사도 업데이트할 수 있습니다.

생성 후 Vercel Blob 스토어 페이지로 이동합니다.

로컬 프로젝트 준비하기

프로젝트에 Blob 스토어를 생성했으므로 다음 환경 변수를 자동으로 생성하고 프로젝트에 추가했습니다.

  • BLOB_READ_WRITE_TOKEN

이 환경 변수를 로컬에서 사용하려면 Vercel CLI를 사용해 불러오는 것이 좋습니다.

vercel env pull .env.development.local

서버 업로드는 Vercel에서 4.5MB보다 큰 파일을 업로드할 필요가 없다면 문제가 없습니다. 더 큰 파일을 업로드해야 한다면 클라이언트 업로드를 고려하세요.

서버 액션을 이용한 파일 업로드

다음 예시는 Next.js 앱 라우터와 서버 액션을 사용하여 Vercel Blob에 파일을 업로드하는 방법을 보여줍니다.

app/components/form.tsx
import { put } from '@vercel/blob';
import { revalidatePath } from 'next/cache';
 
export async function Form() {
  async function uploadImage(formData: FormData) {
    'use server';
    const imageFile = formData.get('image') as File;
    const blob = await put(imageFile.name, imageFile, {
      access: 'public',
    });
    revalidatePath('/');
    return blob;
  }
 
  return (
    <form action={uploadImage}>
      <label htmlFor="image">이미지</label>
      <input type="file" id="image" name="image" required />
      <button>업로드</button>
    </form>
  );
}

그리고 대시보드에서 스토어 ID를 포함하여 next.config.js 파일에 호스트명을 추가하세요.

next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'my-blob-store.public.blob.vercel-storage.com',
        port: '',
      },
    ],
  },
};
 
module.exports = nextConfig;

이 설정을 통해 next/image를 사용하여 Vercel Blob 스토어의 이미지를 표시할 수 있습니다.

app/components/images.tsx
import { list } from '@vercel/blob';
import Image from 'next/image';
 
export async function Images() {
  async function allImages() {
    const blobs = await list();
    return blobs;
  }
  const images = await allImages();
 
  return (
    <section>
      {images.blobs.map((image) => (
        <Image
          priority
          key={image.pathname}
          src={image.url}
          alt="이미지"
          width={200}
          height={200}
        />
      ))}
    </section>
  );
}

서버 액션과 앱 라우터에 대해 더 알고 싶다면 Next.js 문서를 참고하세요.

서버 업로드 페이지와 라우트를 이용한 파일 업로드

라우트 핸들러/API 라우트를 사용하여 Vercel Blob에 파일을 업로드할 수 있습니다. 다음 예시는 서버 업로드 페이지와 라우트를 사용하여 Vercel Blob에 파일을 업로드하는 방법을 보여줍니다.

서버 업로드 페이지 생성하기

이 페이지는 서버에 파일을 업로드하고, 이후 파일을 Vercel Blob으로 전송합니다.

src/app/avatar/upload/page.tsx
'use client';
 
import type { PutBlobResult } from '@vercel/blob';
import { useState, useRef } from 'react';
 
export default function AvatarUploadPage() {
  const inputFileRef = useRef<HTMLInputElement>(null);
  const [blob, setBlob] = useState<PutBlobResult | null>(null);
  return (
    <>
      <h1>아바타 업로드하기</h1>
 
      <form
        onSubmit={async (event) => {
          event.preventDefault();
 
          if (!inputFileRef.current?.files) {
            throw new Error('파일이 선택되지 않았습니다');
          }
 
          const file = inputFileRef.current.files[0];
 
          const response = await fetch(
            `/api/avatar/upload?filename=${file.name}`,
            {
              method: 'POST',
              body: file,
            },
          );
 
          const newBlob = (await response.json()) as PutBlobResult;
 
          setBlob(newBlob);
        }}
      >
        <input name="file" ref={inputFileRef} type="file" required />
        <button type="submit">업로드</button>
      </form>
      {blob && (
        <div>
          Blob URL: <a href={blob.url}>{blob.url}</a>
        </div>
      )}
    </>
  );
}

서버 업로드 라우트 생성하기

이 라우트는 파일을 Vercel Blob으로 전달하고 업로드된 파일의 URL을 브라우저로 반환합니다.

src/app/api/avatar/upload/route.ts
import { put } from '@vercel/blob';
import { NextResponse } from 'next/server';
 
export async function POST(request: Request): Promise<NextResponse> {
  const { searchParams } = new URL(request.url);
  const filename = searchParams.get('filename');
 
  const blob = await put(filename, request.body, {
    access: 'public',
  });
 
  return NextResponse.json(blob);
}

페이지 테스트하기

애플리케이션 로컬에서 실행하기

애플리케이션을 로컬에서 실행하고 /avatar/upload로 이동해 파일을 스토어에 업로드하세요. 브라우저는 파일을 위해 생성된 고유 URL을 표시합니다.

로컬 웹사이트가 http://localhost:3000에서 제공될 때, Vercel Blob이 로컬 호스트에 연락할 수 없기 때문에 onUploadCompleted 단계는 성공하지 않습니다. 대신, ngrok과 같은 터널링 서비스를 통해 로컬 애플리케이션을 실행하여 로컬에서 전체 Vercel Blob 개발 흐름을 경험하는 것이 좋습니다.

Blob 객체 메타데이터 검토하기

  1. 스토어를 생성한 Vercel 프로젝트로 이동하세요.
  2. 스토리지 탭을 선택하고 새로운 스토어를 선택하세요.
  3. 이전 단계에서 반환된 blob 객체 URL을 브라우저 섹션의 Blob URL 입력 상자에 붙여넣고 조회를 선택하세요.
  4. 다음과 같은 blob 객체 메타데이터가 표시됩니다: 파일 이름, 경로, 크기, 업로드 날짜, 콘텐츠 유형 및 HTTP 헤더.
  5. 이 페이지에서 파일을 다운로드하거나 삭제할 수도 있습니다.

Vercel Blob 스토어에 객체를 성공적으로 업로드했으며 Vercel 스토리지 대시보드에서 해당 메타데이터를 검토하고, 다운로드하고, 삭제할 수 있습니다.