React로 파일을 업로드 방법을 정리하려고합니다.
간단한 방법은 아래와 같습니다.
클라이언트 앱(react)
- view 페이지에서 input[type=file] 요소를 적절한 위치에 추가.
- state 추가( state를 이용해서 파일을 업로드하려고합니다.)
- input[type=file] 이벤트 처리 추가
- 전송 버튼 클릭 시 axios 호출 코드 추가
서버 앱(express)
- multer 설치(aws s3에 업로드하려면 multer-s3 설치)
- fileupload 모듈 작성
- 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에 업로드한건데, 잘 저장되는 걸 확인 할 수 있습니다.
'개발 이야기 > React' 카테고리의 다른 글
React로 ProgressBar 구현하기 (0) | 2019.10.04 |
---|---|
Redux-Saga 로 비동기 요청 예제 (0) | 2019.08.18 |
React와 Express 서버 연동 시키기 (0) | 2019.04.28 |
React에서 match와 props (0) | 2019.04.27 |
React용 UI 프레임워크 gestalt 사용해보기 (0) | 2019.04.22 |