NextJS + Fetch + Api 경로 + Typescript로 파일 업로드

React, NextJs 및 Fetch API를 사용하여 파일을 업로드하는 방법을 배웁니다.


우선 다음을 실행하여 NextJs 애플리케이션을 생성해 보겠습니다.

yarn create next-app --typescript


설치가 완료되면 yarn dev를 실행하여 http://localhost:3000에서 개발 서버를 시작합니다.

페이지를 열면 다음과 유사한 내용이 표시됩니다.



이제 양식 데이터를 구문 분석하는 데 도움이 되는 패키지를 설치해 보겠습니다.

yarn add -D formidable @types/formidable



양식 만들기



파일을 업로드할 수 있는 작은 양식을 만들 것입니다. 더 명확하게 하기 위해 코드를 단순화하겠습니다.
pages/index.js로 이동하여 모든 기본 코드를 다음으로 바꿉니다.

import type { NextPage } from 'next'
import React from "react";

const Home: NextPage = () => {

    const [isLoading, setIsLoading] = React.useState(false);
    const inputFileRef = React.useRef<HTMLInputElement | null>(null);

    const handleOnClick = async (e: React.MouseEvent<HTMLInputElement>) => {

        /* Prevent form from submitting by default */
        e.preventDefault();

        /* If file is not selected, then show alert message */
        if (!inputFileRef.current?.files?.length) {
            alert('Please, select file you want to upload');
            return;
        }

        setIsLoading(true);

        /* Add files to FormData */
        const formData = new FormData();
        Object.values(inputFileRef.current.files).forEach(file => {
            formData.append('file', file);
        })

        /* Send request to our api route */
        const response = await fetch('/api/upload', {
            method: 'POST',
            body: formData
        });

        const body = await response.json() as { status: 'ok' | 'fail', message: string };

        alert(body.message);

        if (body.status === 'ok') {
            inputFileRef.current.value = '';
            // Do some stuff on successfully upload
        } else {
            // Do some stuff on error
        }

        setIsLoading(false);
    };

    return (
        <form>
            <div>
                <input type="file" name="myfile" ref={inputFileRef} multiple />
            </div>
            <div>
                <input type="submit" value="Upload" disabled={isLoading} onClick={handleOnClick} />
                {isLoading && ` Wait, please...`}
            </div>
        </form>
    )
}

export default Home


여기서는 여러 파일 업로드를 사용하고 있습니다. 하나의 파일만 업로드하려면 multiple에서 input:file를 제거하십시오.

<input type="file" name="myfile" ref={inputFileRef} />



API 경로



업로드된 파일을 처리할 엔드포인트를 생성해 보겠습니다.
filepages/api/upload.ts를 생성합니다.

import type { NextApiRequest, NextApiResponse } from 'next'
import { promises as fs } from "fs";
import path from "path";
import formidable, { File } from 'formidable';

/* Don't miss that! */
export const config = {
    api: {
        bodyParser: false,
    }
};

type ProcessedFiles = Array<[string, File]>;

const handler = async (req: NextApiRequest, res: NextApiResponse) => {

    let status = 200,
        resultBody = { status: 'ok', message: 'Files were uploaded successfully' };

    /* Get files using formidable */
    const files = await new Promise<ProcessedFiles | undefined>((resolve, reject) => {
        const form = new formidable.IncomingForm();
        const files: ProcessedFiles = [];
        form.on('file', function (field, file) {
            files.push([field, file]);
        })
        form.on('end', () => resolve(files));
        form.on('error', err => reject(err));
        form.parse(req, () => {
            //
        });
    }).catch(e => {
        console.log(e);
        status = 500;
        resultBody = {
            status: 'fail', message: 'Upload error'
        }
    });

    if (files?.length) {

        /* Create directory for uploads */
        const targetPath = path.join(process.cwd(), `/uploads/`);
        try {
            await fs.access(targetPath);
        } catch (e) {
            await fs.mkdir(targetPath);
        }

        /* Move uploaded files to directory */
        for (const file of files) {
            const tempPath = file[1].filepath;
            await fs.rename(tempPath, targetPath + file[1].originalFilename);
        }
    }

    res.status(status).json(resultBody);
}

export default handler;


축하합니다. 완료되었습니다! 양식을 테스트할 수 있습니다!

모든 파일은 프로젝트 루트 내의 디렉터리/uploads에 저장됩니다.


Api 경로를 프록시로 사용



여기서는 파일을 저장하고 파일에 대해 어려운 작업을 수행하고 싶지 않기 때문에 파일을 다른 서버로 전송해야 한다고 가정해 보겠습니다.

몇 가지 새 패키지를 추가합니다.

yarn add -D form-data node-fetch


널 바꿔 /pages/api/upload.ts to :

import type { NextApiRequest, NextApiResponse } from 'next'
import fs from "fs";
import fetch from "node-fetch";
import FormData from 'form-data';
import formidable, { File } from 'formidable';

export const config = {
    api: {
        bodyParser: false,
    }
};

type ProcessedFiles = Array<[string, File]>;

const handler = async (req: NextApiRequest, res: NextApiResponse) => {

    let status = 200,
        resultBody = { status: 'ok', message: 'Files were uploaded successfully' };

    /* Get files using formidable */
    const files = await new Promise<ProcessedFiles | undefined>((resolve, reject) => {
        const form = new formidable.IncomingForm();
        const files: ProcessedFiles = [];
        form.on('file', function (field, file) {
            files.push([field, file]);
        })
        form.on('end', () => resolve(files));
        form.on('error', err => reject(err));
        form.parse(req, () => {
            //
        });
    }).catch(e => {
        console.log(e);
        status = 500;
        resultBody = {
            status: 'fail', message: 'Upload error'
        }
    });

    if (files?.length) {

        /* Add files to FormData */
        const formData = new FormData();
        for (const file of files) {
            formData.append(file[0], fs.createReadStream(file[1].filepath));
        }

        /* Send request to another server */
        const response = await fetch('PATH_TO_ANOTHER_SERVER', {
            headers: formData.getHeaders(),
            method: 'POST',
            body: formData
        });

        // Do anything you need with response

    }

    res.status(status).json(resultBody);
}

export default handler;


교체하는 것을 잊지 마십시오PATH_TO_ANOTHER_SERVER.


이거야, 즐기자! 전체 저장소https://github.com/gapon2401/upload-files-nextjs

좋은 웹페이지 즐겨찾기