Node.js

Node.js + MongoDB 이미지 업로드하기 폴더에저장(multer,path[lib])

svdjcuwg4638 2023. 5. 23. 20:05

무슨 사이트를 운영하든 이미지를 업로드하고 보여줄 일이 많습니다.

이미지는 어떻게 어디에 저장해야하는지 알아보도록 합시다. 

 

1. server.js 근처에 폴더를 하나 만들어서 거기 저장하거나 

2. 아마존 이런데서 하드를 구매해서 거기로 저장하거나 (Amazon S3)   

3. DB에 직접 저장하거나 합니다.

 

하지만 3번은 너무 느리거나 비싸거나 용량문제 때문에 보통 1, 2번 방법을 씁니다.

그리고 이미지를 누가, 어디에, 어떤 이름으로 업로드했는지 같은 메타 정보들은 DB에 저장하는게 일종의 웹개발 관습입니다.  아무튼 우린 1번으로 배워보도록 합시다. 

저장할 이미지가 백만개라면 2번으로 하셔야합니다. 구글에 튜토리얼 100만개 있음 

 

일단 이미지 업로드할 수 있는 페이지를 하나 만들어줍니다

이 새로운 페이지엔 업로드버튼과 전송버튼만 있으면 됩니다. 

그냥 upload.ejs 파일을 이렇게 만들어주시고 

(upload.ejs)

<form method="POST" action="/upload" enctype="multipart/form-data" >
    <input type="file" name="프로필">
    <button type="submit">전송</button>
</form>

(참고로 enctype은 보내는 파일의 인코딩형식이며 파일, 이미지업로드시엔 multipart 어쩌구라고 적어주시는게 좋습니다)

 

서버는 하단과같이 작성해서 /upload로 방문시 upload.ejs를 보여주도록 합시다. 

(server.js)

app.get('/upload', function(요청, 응답){
  응답.render('upload.ejs')
}); 

 

 

업로드한 이미지를 하드에 저장합시다 

사용자가 업로드한 이미지는 그냥 우리 서버돌리는 컴퓨터에 그대로 저장을 해보도록 합시다. 

우리 작업폴더안에 public/image라는 폴더를 하나 만들어서 거기다가 다 몰아넣을겁니다. 

그 일을 쉽게하려면 일단 라이브러리가 하나 필요합니다. 

 

터미널 키셔서

npm install multer 

라고 입력해줍니다.

위 라이브러리는 multipart/form-data를 통해 업로드된 파일을 매우 쉽게 저장, 이름변경, 처리할 수 있게 도와주는 라이브러리입니다. 

 

그리고 설치가 끝났으면 server.js에서 multer 셋팅을 이렇게 해주시면 됩니다. 

let multer = require('multer');
var storage = multer.diskStorage({

  destination : function(req, file, cb){
    cb(null, './public/image')
  },
  filename : function(req, file, cb){
    cb(null, file.originalname )
  }

});

var upload = multer({storage : storage});

require 어쩌구는 multer 설치한거 갖다쓰겠습니다~ 라는 뜻이고

그 밑에는 전부 셋팅입니다. 이런건 라이브러리 사용법일 뿐이라 이해의 영역이 아닙니다. 암기와 복붙의 영역입니다. 

 

1. diskStorage라는 함수를 쓰면 업로드된 파일을 하드에 저장할 수 있습니다. memoryStorage라고 쓰시면 하드 말고 램에 저장할 수 있습니다 (휘발성)

2. destination : 업로드된 파일을 하드 어떤 경로에 저장할지 정하는 부분입니다. 알아서 정하십쇼 

3. filename : 파일의 이름을 결정하는 부분입니다. 저장할 때 어떤 이름으로 저장할겁니까. file.originalname이라고 쓰면 그냥 원본 그대로라는 뜻입니다. 

(filename에서 한글사진파일을 이름이깨지는데 받와와서 번호로 사진이름을 저장하거나 영문으로 저장하던지 하자 한글안깨지고 받는법은 복잡하다 그게 중복도 안되고 좋다)

 

나중에 file.originalname + '오늘날짜~' 이런 식으로 저장하면 중복없이 유니크하게 저장할 수도 있겠군요? 

 

4. 그리고 마지막줄에서 var upload라는 변수를 만들고 multer 셋팅을 다 저장해주시면 됩니다. 끝!

 

업로드한 파일의 확장자 필터로 원하는 파일만 거르는 법

var path = require('path');

var upload = multer({
    storage: storage,
    fileFilter: function (req, file, callback) {
        var ext = path.extname(file.originalname);
        if(ext !== '.png' && ext !== '.jpg' && ext !== '.jpeg') {
            return callback(new Error('PNG, JPG만 업로드하세요'))
        }
        callback(null, true)
    },
    limits:{
        fileSize: 1024 * 1024
    }
});

 

▲ 셋팅하는 부분 안에 fileFilter라는 항목을 추가해주시면 됩니다.

path라는 변수는.. nodejs 기본 내장 라이브러리 path 라는걸 활용해 파일의 경로, 이름, 확장자 등을 알아낼 때 사용합니다. 

위의 예제에서는 업로드한 파일의 확장자를 알아내서 png랑 맞는지 비교하는 과정입니다. 

limits는 파일의 사이즈 제한을 걸고 싶을 때 씁니다. 1024 * 1024는 1MB를 뜻합니다. 

 

셋팅이 완료되었으면 누군가 폼으로 이미지를 전송할 때 실행해보도록 합시다. 

그건 역시나 server.js에다가 app.post 어쩌구 하면 되겠습니다. 

app.post('/upload', upload.single('프로필'), function(요청, 응답){
  응답.send('업로드완료')
}); 

근데 미들웨어처럼 실행시켜주시면 됩니다. 

미들웨어는 요청과 응답 사이에 실행하는 코드랬죠? 

누군가 /upload로 POST 요청을 하면 upload.single('input의name속성') 을 실행시키시면 됩니다. 

그럼 multer 셋팅한대로 알아서 지가 업로드한 파일을 처리해줍니다. 

 

 

* input의 name속성 적으라는 곳에는 파일 업로드시킬 input의 name 속성명을 진짜로 적으시면 됩니다. 

 

그럼 /upload 페이지 들어가서 실제 사진 업로드 테스트해보십시오. 

전송버튼까지 누르면 업로드한 사진이 public/image 폴더 안에 저장됩니까? 

저장이 잘 됩니다. 성공!

 

업로드한 이미지 보여주는 법 (이미지 API 만들기)

그냥 이렇게 서버코드를 짜면 됩니다.

"누가 /image/music.jpg로 접속하면 music.jpg 파일을 보내줌"

이게 끝입니다. app.get 하면 될 것 같지 않습니까. 맞습니다. 

app.get('/image/:imageName', function(요청, 응답){
  응답.sendFile( __dirname + '/public/image/' + 요청.params.imageName )
})

누군가 /image/:파라미터 로 접속하면

/public/image/:파라미터 라는 파일을 보내주세요~ 라는 코드입니다. 

그냥 일반 파일을 유저에게 보내고 싶으면 sendFile이라는 함수를 쓰면 됩니다. 

그리고 __dirname은 특별한 기본 변수인데 출력해보시면 그냥 현재 파일의 경로가 나옵니다. 

그래서 현재 server.js 경로 + /public/image/ + 파라미터라고 입력해준겁니다. 그럼 원하는 이미지가 나오겠군요. 

 

실제로 브라우저에서 /image/music.jpg 라고 접속하면 아까 업로드한 파일이 잘 나오네요 성공!

 

저장된 파일을 홈페이지에 보여주고싶다면

<img src = "/image/dizin.jpg">

위와같이 html이나 ejs파일에 추가하면 위치에 저장된 사진이 불러오게된다.

 

클라우드에서 사용한다면?

아마존 같은 클라우드 서비스에서 하드를 구매하셨다면 과정이 대충 이렇게 쉽습니다.

0. id가 admin인 유저가 마이페이지에서 자기 프로필 사진을 업로드합니다. 

1. 그럼 서버는 뭘해야하냐면.. 이미지 저장 요청이 들어오면 아마존에서 제공하는 예제코드를 실행하시면 됩니다. 그럼 아마존 하드에 저장해줌

2. 저장이 성공하면 아마존에서 이미지 URL을 퉤 뱉어줍니다. amazon.com/image/music.jpg 대충 이렇다고 칩시다. 

3, 그 amazon.com/image/music.jpg 이라는 URL을 프로필 이미지만 따로 모아놓은 MongoDB document에 { id : admin, 프로필이미지 : amazon.com/image/music.jpg } 이런 정보를 저장합니다. 이미지 URL와 이미지가 누구 것인지의 정보를 저장하는 셈이죠? 그럼 저장과정 끝!

4. 이미지 보여주기는 더 쉽습니다. 그 이미지가 필요한 페이지에선 amazon.com/image/music.jpg 이라는 URL을 DB에서 불러와서 <img> 태그 안에 넣기만 하시면 됩니다.