[TIL] Nodejs - 클라이언트측에서 받은 이미지를 base64로 인코딩

·2023년 6월 29일
1

TIL

목록 보기
6/7
post-thumbnail

해결한 지금 상황에서 봤을 땐, 되게 별거 아닌데 해결하기 전까지는 답을 모르겠어서 프론트 하는 분과 같이 너무 많이 헤맸다🥹🥹
그리고 이제와 떠오른건 EC2를 왜 안썼을까 ... 라는 생각..


✔️상황1 (이미지 받기+저장)

  • 클라이언트측 요청: 여러가지 문자열 데이터값+ 이미지 파일 (multipart/form-data)
    -> 데이터 값(string): userId, petName, 이미지(file): petImg
  • 서버측 행위: 요청값들을 DB에 저장
  • 서버측 응답: status값 전송 (success or false)

api 주소 - upload 이용

우선 이미지를 받으려면, 아래와 같이 upload.single('~')을 이용해야한다. 여기서 petImg는 클라이언트 측에서 이미지를 받을 때 통일시켜야 하는 변수의 값이다. 이 변수명을 img로 지정한다면, 클라이언트에서도 img라는 이름으로 이미지 파일을 보내줘야한다.

petRouter.post('/register', upload.single('petImg'), petController.petRegister)

클라이언트측에서 데이터값(문자열) 받기

userIdpetName값을 클라이언트 측에서 받는건 굉장히 단순하다.

var userId = req.body.userId;
var petName = req.body.petName;

클라이언트측에서 이미지값(파일) 받기

파일도 마찬가지로, 문자열 형식인 데이터를 받는 것과 동일하다.

const file = req.file;

✔️상황2 (클라이언트측에서 이미지 요청)

  • 클라이언트측 요청: userId값에 따른 petName과 해당 pet의 이미지(petImg)
  • 서버측 응답: 요청받은 userId를 통해 DB 조회하여 해당 값 전달

여기서 내가 헤맸던 이유는 두가지다.

  1. json형식의 데이터값과 file 형식의 이미지값을 같이 어떻게 보내야할지
  2. 이미지 값을 어떤식으로 DB에 넣어야 조회했을 때 온전히 이미지 값을 확인할 수 있을지
    • 결과적으로 이 2번 문제를 해결하는게 핵심이다

❌ 1번 문제

처음에 시도했던 방법은, json형식의 문자열 데이터와 file형식의 이미지 데이터를 같이 보내려고 했다. 하지만, 기본적으로 res.jsonres.send는 같이 진행될 수 없도록 되어있다. 반환하는 것이 두 개로 이루어지기 때문이다.

원래 api가 달랐다면, 문자열 데이터는 아래와 같이 단순히 res.json을 이용하고,

res.json({
	userId: userId,
  	petName: petName
})

이미지 데이터는 res.send를 이용하여 전송하면 된다.

res.send(file)

근데 이 두 가지가 한꺼번에 진행될 수 없으므로, 다른 방법을 이용하였다.


⭕ 2번 문제- base64로 이미지 인코딩💡

2번 문제를 해결하는 방법은 다음과 같다.

  1. 우선, 받은 이미지 값을 base64로 인코딩한다.
  2. 인코딩된 이미지 값(문자열)을 다른 데이터 값들과 같이 DB에 저장한다.
  3. 프론트측에서는 이 인코딩된 이미지 값을 받으면, 디코딩하여 UI에 띄울 수 있도록 한다.

내가 헤맸던 이유는, 인코딩된 이미지를 프론트측에서 풀어서 볼 수 있다는걸 몰랐기 때문이다. 그래서 아예 이 생각을 하지 못했는데.. 이제라도 알았으니 오히려 다행이다.

정리하면 아래와 같이 진행되며 처리 과정이 두 가지로 나뉜다.

  • 위: 클라이언트에서 전송한 값 (문자열+이미지)을 DB에 저장
  • 아래: DB에 저장된 값을 조회


클라이언트에서 전송한 값 (문자열+이미지)을 DB에 저장

exports.petRegister = (req, res) => {

  	// 클라이언트측에서 보내는 데이터 받기
    var userId = req.body.userId;
    var petName = req.body.petName;
    var file = req.file; //이미지

  	
    var imgName = file.filename;
  	// 이미지 저장할 위치 지정
    var filePath = path.join(__dirname, '..', 'main', 'uploads', imgName);
    var imageBuffer = fs.readFileSync(filePath);
  	// base64로 이미지 인코딩
    var encode = Buffer.from(imageBuffer).toString('base64');
	
  	// DB table에 userId, petName, petImg(인코딩된 값)을 Insert
    db.query('INSERT INTO pet (petIdx, userId, petName, petImg) VALUES (?,?,?)', [null, userId, petName, encode], function (error, data) {
      	// 오류 발생
        if (error) {
            return res.status(500).json({ error: error.message });
        }
		// 정상적으로 등록 성공
        res.json({
            status: "success"
        })
    })
}

DB에 저장된 값을 조회

exports.petMain = (req, res) => {
    var userId = req.body.userId;

  	// userId 값에 따른 데이터 조회
    db.query('SELECT userId, petName, CONVERT(petImg USING utf8) as petImg FROM pet WHERE userId = ?', [userId], function (error, result) {
        if (error) {
            return res.status(500).json({ error: error.message });
        }
        res.json({
            status: "success",
            result: result
        })
    })
}

postman 결과

프론트측에서 받고 처리하는 부분은 내가 하는 부분이 아니라 잘 모르겠지만, Nodejs는 이런식으로 값을 받고 전달한다.
(프론트 맡은 분이 작성하신 글은 아래에 첨부해두었다)

  • pet 등록

  • 등록된 pet 조회 (이미지 값은 엄청 길다)


✔️ 이와 관련된 프론트 부분 (Android)

https://dvlpseo.tistory.com/76

0개의 댓글