본문 바로가기
개발 이야기/React

React 이미지 파일 업로드 하기

by 농개 2019. 6. 24.
반응형

React로 파일을 업로드 방법을 정리하려고합니다.

간단한 방법은 아래와 같습니다.

 

클라이언트 앱(react)

  1. view 페이지에서 input[type=file] 요소를 적절한 위치에 추가.
  2. state 추가( state를 이용해서 파일을 업로드하려고합니다.)
  3. input[type=file] 이벤트 처리 추가
  4. 전송 버튼 클릭 시 axios 호출 코드 추가

서버 앱(express)

  1. multer 설치(aws s3에 업로드하려면 multer-s3 설치)
  2. fileupload 모듈 작성
  3. route에서 upload 코드 추가

 

먼저 클라이언트앱을 작성해봅시다.

 

01. view 페이지에 input[type=file] 추가

./src/App.js

import React, { Component } from 'react'

class App extends Component {
  render() {
    return (
      <div>
        <input type="file" name="file" onChange={null}/>
        <button type="button" onClick={null}/>
      </div>
    )
  }
}

export default App

위와 같이 추가 했습니다. onChange, onClick은 추후 이벤트 처리 함수를 대입해야 합니다.

 

 

 

02. state 추가

./src/App.js

import React, { Component } from 'react'

class App extends Component {
  constructor(props){
    super(props);
    this.state = {
      selectedFile: null,
    }
  }
  
  render() {
    return (
      <div>
        <input type="file" name="file" onChange={null}/>
        <button type="button" onClick={null}/>
      </div>
    )
  }
}

export default App

constructor를 추가하고 selectedFile이라는 state을 추가해줍니다. 초기값은 null이구요

 

이제 state에다가 파일객체를 담아서 서버로 업로드 요청을 보내기만 하면 됩니다.

 

 

 

 

03. onChange, onClick 이벤트 처리 추가

import React, { Component } from 'react'
import axios from 'axios';

class App extends Component {
  constructor(props){
    super(props);
    this.state = {
      selectedFile: null,
    }
  }

  handleFileInput(e){
    this.setState({
      selectedFile : e.target.files[0],
    })
  }

  handlePost(){
    const formData = new FormData();
    formData.append('file', this.state.selectedFile);

    return axios.post("/api/upload", formData).then(res => {
      alert('성공')
    }).catch(err => {
      alert('실패')
    })
  }

  render() {
    return (
      <div>
        <input type="file" name="file" onChange={e => this.handleFileInput(e)}/>
        <button type="button" onClick={this.handlePost()}/>
      </div>
    )
  }
}

export default App

onChange : input 태그를 클릭하여 파일을 선택하면 해당 이벤트가 호출됩니다. setState를 하게됩니다.

onClick : FormData를 만들어서 file이라는 이름의 arument에 file객체를 담고, API서버(express)로 POST요청을 합니다.

 

 

 

자 이제 서버쪽 코드를 만져봅시다.

 

04. multer 추가

npm install --save multer moment

multer라는 라이브러리를 사용할겁니다. 아주 유용하고 많이 사용하는 인기있는 라이브러리입니다.

moment는 시간과 관련된 라이브러리로 저는 얘를 애용합니다.ㅎ

 

05. fileupload 모듈 작성

./server/fileupload.js

const multer = require('multer');
const moment = require('moment');

const storage = multer.diskStorage({
  destination: function(req, file, cb) {
    cb(null, 'uploads');  // 파일이 저장되는 경로입니다.
  },
  filename: function(req, file, cb) {
    cb(null, moment().format('YYYYMMDDHHmmss') + "_" + file.originalname);  // 저장되는 파일명
  }
});

const upload = multer({ storage: storage }).single("file");   // single : 하나의 파일업로드 할때

module.exports = upload;

위와 같이 작성하면 됩니다.

경로를 uploads라고 지정하고, 요청을 하게 되면 아래와 같은 디렉토리가 생성되어 저장될 것입니다.(./uploads)

 

 

아래는 s3에 업로드 할때 코드입니다.

const aws = require('aws-sdk');
const multer = require('multer');
const multerS3 = require('multer-s3');
const moment = require('moment');

const s3 = new aws.S3({
  accessKeyId: 'accesskey', // 생성한 s3의 accesskey 
  secretAccessKey: 'secretaccesskey', // 생성한 s3의 secret key 
  region: 'region'  // 지역설정 
})

const storage = multerS3({
  s3: s3,
  bucket: 'bucketname', // s3 생성시 버킷명
  acl: 'public-read',   // 업로드 된 데이터를 URL로 읽을 때 설정하는 값입니다. 업로드만 한다면 필요없습니다.
  metadata: function (req, file, cb) {
    cb(null, {fieldName: file.fieldname}); // 파일 메타정보를 저장합니다.
  },
  key: function (req, file, cb) {
    cb(null, moment().format('YYYYMMDDHHmmss') + "_" + file.originalname) // key... 저장될 파일명과 같이 해봅니다.
  }
})

const upload = multer({ storage: storage }).single("file");

module.exports = upload;

물론 aws-sdk, multer-s3 설치해줘야 합니다.

 

 

 

06. route 에서 upload 사용

./server/route/index.js

const express = require("express");
const upload = require('../fileupload');
const multer = require('multer');

const router = express.Router();

router.post("api/upload", (req, res, next) => {
  // FormData의 경우 req로 부터 데이터를 얻을수 없다.
  // upload 핸들러(multer)를 통해서 데이터를 읽을 수 있다
  
  upload(req, res, function(err) {
    if (err instanceof multer.MulterError) {
      return next(err);
    } else if (err) {
      return next(err);
    }
    console.log('원본파일명 : ' + req.file.originalname)
    console.log('저장파일명 : ' + req.file.filename)
    console.log('크기 : ' + req.file.size)
    // console.log('경로 : ' + req.file.location) s3 업로드시 업로드 url을 가져옴
    return res.json({success:1});
  });
});

앞서 작성한 upload모듈을 임포트 해줍니다.

그리고 route에 upload를 먼저 사용해줍니다.(주석에 쓰여져있지만, FormData가 서버로 전송되었을때

router의 req에서는 파일정보를 얻을 수 없습니다. 앞서 작성한 multer를 통해 req를 얻어야만

클라이언트에서 전송한 데이터를 읽을 수 있습니다. 

 

 

아래는 s3에 업로드한건데, 잘 저장되는 걸 확인 할 수 있습니다.

 

반응형