express, react 이미지 업로드 서버

파쏭쏭계란빡 ㅣ 2023. 9. 17. 23:55

간단한 이미지 업로드 서버와 클라이언트를 만들어본다.

서버는 express 사용 및 이미지 업로드를 위해서 middle ware인 multer를 사용한다.

multipart/form-data 형식으로 단일 및 다중 파일 업로드를 지원하기 때문에 가장 많이 사용한다.

※ 멀티파트 형식이란 enctype이 multipart/form-data 인 폼을 통해 업로드하는 데이터의 형식을 의미한다

서버

기본 express 설정

express 설치

npm init -y
npm i express
npm i -D nodemon

 

server.js 파일 추가

//🏴‍☠️ server.js

console.log("헬로월드");

 

nodemon으로 server.js 실행

{
    "name": "server",
    "version": "1.0.0",
    "description": "",
    "main": "server.js",
    "scripts": {
        "dev": "nodemon server.js"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "dependencies": {
        "express": "^4.18.2"
    },
    "devDependencies": {
        "nodemon": "^3.0.1"
    }
}

 

기본 express 서버 설정

//🏴‍☠️ server.js

const express = require("express");

const app = express();
const PORT = 5000;

app.listen(PORT, () => console.log(`서버 ${PORT}번 살아있음~🚗`));

 

기본 라우터 추가

//🏴‍☠️ server.js
const express = require("express");

const app = express();
const PORT = 5000;

//라우터 추가
app.post("/upload", (req, res) => {
    console.log("/업로드 요청~!");
    res.json({ result: "성공~" });
});

app.listen(PORT, () => console.log(`서버 ${PORT}번 살아있음~🚗`));

 

post man으로 api 요청 성공

multer로 이미지 업로드 api 만들기

이미지 업로드 플러그인 multer 사용

npm i multer

 

지원하는 미들웨어 종류

  • storage는 저장할 공간에 대한 정보. 디스크나 메모리 저장 가능.
  • diskStorage는 하드디스크에 업로드 파일을 저장한다는 것
  • destination은 저장할 경로
  • filename은 저장할 파일명(파일명+날짜+확장자 형식)
  • Limits는 파일 개수나 파일 사이즈를 제한할 수 있음.

 

multer 모듈 적용 코드

var multer = require('multer'); // express에 multer모듈 적용 (for 파일업로드)
var upload = multer({ dest: 'uploads/' })
// 입력한 파일이 uploads/ 폴더 내에 저장된다.
// multer라는 모듈이 함수라서 함수에 옵션을 줘서 실행을 시키면, 해당 함수는 미들웨어를 리턴한다.

 

multer - 저장경로, 파일명 설정

multer 모듈을 통해서 post로 전송된 파일의 저장경로와 파일명 등을 처리하기 위해서는 DiskStorage 엔진이 필요

var multer = require('multer'); // multer모듈 적용 (for 파일업로드)
var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, 'uploads/') // cb 콜백함수를 통해 전송된 파일 저장 디렉토리 설정
  }
  filename: function (req, file, cb) {
    cb(null, file.originalname) // cb 콜백함수를 통해 전송된 파일 이름 설정
  }
})
var upload = multer({ storage: storage })

express 서버에 적용하기

multer 미들웨어를 통해서 uploads 폴더에 이미지 추가

라우터의 두번째 파라미터에 key 맞춰주기

//🏴‍☠️ server.js
const express = require("express");
const multer = require("multer"); //multer 미들웨어 추가
const upload = multer({ dest: "uploads" }); //uploads 폴더에 요청한 이미지 저장

const app = express();
const PORT = 5000;

//라우터 추가
app.post("/upload", upload.single("imageTest"), (req, res) => {
    console.log(req.file);
    res.json(req.file);
});

app.listen(PORT, () => console.log(`서버 ${PORT}번 살아있음~🚗`));

 

post man으로 body의 form에 key 맞춰서 요청

 

uploads 폴더에 요청한 파일 저장 완료

 

파일 저장 과정 제어를 위해 코드 수정

//🏴‍☠️ server.js
const express = require("express");
const multer = require("multer"); //multer 미들웨어 추가
const storage = multer.diskStorage({
    destination: (req, file, cb) => cb(null, "./uploads"),
    filename: (req, file, cb) => cb(null, file.originalname),
});
const upload = multer({ storage });
const app = express();
const PORT = 5000;

//라우터 추가
app.post("/upload", upload.single("imageTest"), (req, res) => {
    console.log(req.file);
    res.json(req.file);
});

app.listen(PORT, () => console.log(`서버 ${PORT}번 살아있음~🚗`));

업로드한 이미지 이름 고유한 id로 저장하기

uuid 생성

npm i uuid

uuid 사용하기

- filename: (req, file, cb) => cb(null, uuid()) uuid를 추가해주자

//🏴‍☠️ server.js
const express = require("express");
const multer = require("multer"); //multer 미들웨어 추가
const { v4: uuid } = require("uuid"); //uuid 추가


const storage = multer.diskStorage({
    destination: (req, file, cb) => cb(null, "./uploads"),
    filename: (req, file, cb) => cb(null, uuid()),//uuid 사용
});
const upload = multer({ storage });
const app = express();
const PORT = 5000;

//라우터 추가
app.post("/upload", upload.single("imageTest"), (req, res) => {
    console.log(req.file);
    res.json(req.file);
});

app.listen(PORT, () => console.log(`서버 ${PORT}번 살아있음~🚗`));

 

uuid를 이용해서 파일 이름 생성

파일 확장자 제어

mime-types 설치

npm i mime-types

 

.${mime.extension(file.mimetype)} 추가해서 uuid뒤에 파일 확장자 추가

const storage = multer.diskStorage({
    destination: (req, file, cb) => cb(null, "./uploads"),
    filename: (req, file, cb) =>
        cb(null, `${uuid()}.${mime.extension(file.mimetype)}`), //uuid 사용 + 파일 확장자 제어
});
//🏴‍☠️ server.js
const express = require("express");
const multer = require("multer"); //multer 미들웨어 추가
const { v4: uuid } = require("uuid"); //uuid 추가
const mime = require("mime-types"); //파일 확장자 제어
const storage = multer.diskStorage({
    destination: (req, file, cb) => cb(null, "./uploads"),
    filename: (req, file, cb) =>
        cb(null, `${uuid()}.${mime.extension(file.mimetype)}`), //uuid 사용 + 파일 확장자 제어
});
const upload = multer({ storage });
const app = express();
const PORT = 5000;

//라우터 추가
app.post("/upload", upload.single("imageTest"), (req, res) => {
    console.log(req.file);
    res.json(req.file);
});

app.listen(PORT, () => console.log(`서버 ${PORT}번 살아있음~🚗`));

 

사용자가 업로드한 확장자 이름으로 파일 명 생성

저장한 파일 조회 - static 파일 제공

정적인 파일이 위치할 디렉토리의 이름 선언 (app_file.js)

정적인 파일이 접근할 라우터 path 설정
(express.static 함수를 통해 제공되는 파일에 대한 가상 경로)

app.use('/users', express.static('uploads'));

 

이를 통해서 /users 경로를 통해 uploads 디렉토리에 포함된 파일을 로드할 수 있음
(ex. http://localhost:3000/users/siwa.png)

 

app.use(express.static()) 이용해서 외부에 노출 시킬 폴더 지정

app.use("/uploads", express.static("uploads")); //uploads 폴더 외부 노출
//🏴‍☠️ server.js
const express = require("express");
const multer = require("multer"); //multer 미들웨어 추가
const { v4: uuid } = require("uuid"); //uuid 추가
const mime = require("mime-types"); //파일 확장자 제어
const storage = multer.diskStorage({
    destination: (req, file, cb) => cb(null, "./uploads"),
    filename: (req, file, cb) =>
        cb(null, `${uuid()}.${mime.extension(file.mimetype)}`), //uuid 사용 + 파일 확장자 제어
});
const upload = multer({ storage });
const app = express();
const PORT = 5000;

app.use("/uploads", express.static("uploads")); //uploads 폴더 외부 노출

//라우터 추가
app.post("/upload", upload.single("imageTest"), (req, res) => {
    console.log(req.file);
    res.json(req.file);
});

app.listen(PORT, () => console.log(`서버 ${PORT}번 살아있음~🚗`));

 

localhost:5000/파일이름 접근 시 이미지 파일 접근 가능

 

이렇게 안하면 접근 불가능하다

이미지 저장 필터 걸기

사진 파일만 올리기 위해서 fileFilter 추가

const upload = multer({
    fileFilter: (req, file, cb) => {
        //파일 확장자 제어
        if (
            ["image/png", "image/jpeg", "image/jpg", "image/gif"].includes(
                file.mimetype
            )
        ) {
            cb(null, true);
        } else {
            cb(new Error("invalid file type.", false));
        }
    },
});
//🏴‍☠️ server.js
const express = require("express");
const multer = require("multer"); //multer 미들웨어 추가
const { v4: uuid } = require("uuid"); //uuid 추가
const mime = require("mime-types"); //파일 확장자 제어
const storage = multer.diskStorage({
    destination: (req, file, cb) => cb(null, "./uploads"),
    filename: (req, file, cb) =>
        cb(null, `${uuid()}.${mime.extension(file.mimetype)}`), //uuid 사용 + 파일 확장자 제어
});
const upload = multer({
    storage,
    fileFilter: (req, file, cb) => {
        //파일 확장자 제어
        if (
            ["image/png", "image/jpeg", "image/jpg", "image/gif"].includes(
                file.mimetype
            )
        ) {
            cb(null, true);
        } else {
            cb(new Error("invalid file type.", false));
        }
    },
});
const app = express();
const PORT = 5000;

app.use("/uploads", express.static("uploads")); //uploads 폴더 외부 노출

//라우터 추가
app.post("/upload", upload.single("image"), (req, res) => {
    console.log(req.file);
    res.json(req.file);
});

app.listen(PORT, () => console.log(`서버 ${PORT}번 살아있음~🚗`));

 

파일 사이즈 제한

const upload = multer({
    //파일 사이즈 제한
    limits: {
        fileSize: 1024 * 1024 * 5,
    },
});
//🏴‍☠️ server.js
const express = require("express");
const multer = require("multer"); //multer 미들웨어 추가
const { v4: uuid } = require("uuid"); //uuid 추가
const mime = require("mime-types"); //파일 확장자 제어
const storage = multer.diskStorage({
    destination: (req, file, cb) => cb(null, "./uploads"),
    filename: (req, file, cb) =>
        cb(null, `${uuid()}.${mime.extension(file.mimetype)}`), //uuid 사용 + 파일 확장자 제어
});
const upload = multer({
    storage,
    fileFilter: (req, file, cb) => {
        //파일 확장자 제어
        if (
            ["image/png", "image/jpeg", "image/jpg", "image/gif"].includes(
                file.mimetype
            )
        ) {
            cb(null, true);
        } else {
            cb(new Error("invalid file type.", false));
        }
    },
    //파일 사이즈 제한
    limits: {
        fileSize: 1024 * 1024 * 5,
    },
});
const app = express();
const PORT = 5000;

app.use("/uploads", express.static("uploads")); //uploads 폴더 외부 노출

//라우터 추가
app.post("/upload", upload.single("image"), (req, res) => {
    console.log(req.file);
    res.json(req.file);
});

app.listen(PORT, () => console.log(`서버 ${PORT}번 살아있음~🚗`));

클라이언트

create-reat-app 설치

npx create-react-app client

 

기본적인 클라이언트 소스 코드

import React, { useState } from "react";
import axios from "axios";

const UploadForm = () => {
    const [file, setFile] = useState(null);
    const [fileName, setFileName] = useState("이미지 파일을 업로드 해주세요");

    const handleImageSelect = (e) => {
        const imageFile = e.target.files[0];
        console.log({ imageFile });
        setFile(imageFile);
        setFileName(imageFile.name);
    };

    const onSubmit = async (e) => {
        e.preventDefault();
        console.log("제출");
        const formData = new FormData();
        formData.append("image", file); //서버의 upload.single("image") 이 부분이랑 key 맞춰줘야함

        const res = await axios.post("/upload", formData, {
            headers: { "Content-type": "multipart/form-data" },
        });
        console.log({ res });
        alert("성공");

        try {
        } catch (err) {
            alert("실페");
            console.log(err);
        }
    };

    return (
        <form onSubmit={onSubmit}>
            <label htmlFor="image">{fileName}</label>
            <input id="image" type="file" onChange={handleImageSelect} />
            <button type="submit">제출</button>
        </form>
    );
};

export default UploadForm;

'node.js' 카테고리의 다른 글

node.js next 함수를 이용한 Express 미들웨어 실행  (0) 2024.01.04
몽고db 기본 연결  (0) 2023.09.19
express, react 이미지 업로드 서버