nonneng.ee
Daeun-rithm
nonneng.ee
전체 방문자
오늘
어제
  • 분류 전체보기 (51)
    • Back-end (17)
      • Server (3)
      • Database (3)
      • Spring (9)
      • Node.js (1)
    • Book (1)
      • 이펙티브 자바 (0)
      • 대규모 시스템 설계 (1)
    • Algorithm (1)
      • Greedy, Implementation (6)
      • Dynamic Programming (5)
      • Data Structure (3)
      • Sorting (2)
      • Concept (1)
    • TIL (11)
    • Software (3)
      • Design Pattern (3)
    • Computer Science (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 백준
  • Spring
  • 이펙티브 자바
  • Java
  • Postman
  • 수동설치
  • 구동원리
  • 아이템9
  • APM
  • 컴파일설치
  • 아이템 25
  • API
  • 소스설치
  • 구현
  • 아이템 23
  • node js
  • 파이썬
  • 서버
  • 자바
  • 우분투
  • 가상머신
  • jwt
  • Restful API
  • DP
  • MySQL
  • 아이템6
  • 브루트포스
  • JPA
  • 아이템8
  • 에러

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
nonneng.ee

Daeun-rithm

[AWS S3/Node.js] 안드로이드에서 서버로 이미지 전송하기
Back-end/Node.js

[AWS S3/Node.js] 안드로이드에서 서버로 이미지 전송하기

2022. 2. 9. 08:54

지금까지 Aniverse 프로젝트를 진행하면서, 클라이언트 ↔ 서버간 이미지를 전송할 때, 임시로 깃허브 이슈를 통해 생성한 이미지 링크를 전송하는 방식으로 진행했다. (ex. 140559373-3d9b5f13-e1e4-4a51-80ae-b9cdf72769eb.png (474×440) (user-images.githubusercontent.com))

 

이번에 사용자 휴대폰의 갤러리에서 직접 사진을 선택하여 서버에 올릴 수 있도록 수정했다. Amazon에서 제공하는 bucket을 이용하였고, 다음 그림은 우리가 개발하고자 하는 방식이다.

  1. F) 클라이언트에서 이미지를 얻어 base64 방식으로 인코딩
  2. F → B) base64로 인코딩된 문자열을 서버에게 전송
  3. B) 문자열을 디코딩하여 이미지 얻어내기
  4. 얻어낸 이미지를 .jpg 형식으로 서버 내에 저장
  5. 해당 이미지를 AWS bucket에 객체로 등록 → 어디에서나 접근 가능한 링크 생성
  6. DB에는 생성한 링크 저장
  7. 이미지 요청이 들어오면, DB에서 링크를 전송

 

💡 1. AWS 버킷 생성

사용한 AWS S3는 아마존에서 제공하는 온라인 스토리지 웹 서비스이다. 다양한 기능을 필요로 하지 않았으므로 Lightsail을 사용했다.

버킷을 생성하면 다음과같이 오브젝트들을 등록할 수 있고, 고유 도메인이 생성된다. 접근 권한을 public으로 설정하면, “해당 도메인/객체 이름”으로 누구나 해당 객체에 접근할 수 있게된다. (ex. tokiki5 (450×300) (bucket-54ci7a.s3.ap-northeast-2.amazonaws.com))

 

💡 2. 서버에 필요한 모듈 설치

$ npm install --save express aws-sdk multiparty

 

💡 3. Controller에 버킷, 필요한 모듈 등록

  • adoptController
const fs = require('fs');
const { constants } = require('buffer');
const AWS = require('aws-sdk');
const BUCKET_NAME = 'bucket-54ci7a'
AWS.config.update({
    region:         'ap-northeast-2',
    accessKeyId:    'AKIA5EBOBS6LWTZ',
    secretAccessKey:'S7k01bdix5e04m1Hx0GVE6/2xMnlvfJ'
})

이미지를 서버에 저장하고, 버킷에 등록하기 위해 추가적으로 필요한 코드이다. accesskeyId와 secretAccessKey는 버킷을 생성한 뒤 발급받을 수 있다. secretAccessKey는 발급시점 딱 한번만 보여지니 주의!

 

💡 4. base64 디코딩 코드

  • adoptController - 동물정보 업로드 API
    // base64포멧의 스트링을 디코딩하여 파일로 쓰는 함수
    function base64_decode(base64str, file) {
        // 버퍼 객체를 만든후, 인자 <=> (base64 스트링, 파일 경로)
        var bitmap = new Buffer(base64str, 'base64');
        // 버퍼의 파일을 쓰기
        fs.writeFileSync(file, bitmap);
    }
	
        var filename = animalSpecies + animalAge; // 파일명 변수
        console.log('filename : ', filename);

        var filepath = 'filefile/' + filename + '.jpg'; // 파일경로 (서버에서의 상대경로)
        console.log('filepath : ', filepath);

        base64_decode(animalImage, filepath);  // 함수 실행

 

💡 5. AWS 버킷에 이미지 등록하는 코드

  • adoptController - 동물정보 업로드 API
        const imageStream = fs.createReadStream(filepath);

        const params = { Bucket:BUCKET_NAME, Key:filename, Body:imageStream, ContentType: 'image' }
        const upload = new AWS.S3.ManagedUpload({ params });
        upload.promise()

 

💡 최종 코드

/**
 * Adopt 1.2 동물정보 업로드 API
 * [POST] /adopt/animalinfo
 */
exports.postAdoptAnimalInfo = async function (req, res) {

		// base64포멧의 스트링을 디코딩하여 파일로 쓰는 함수
    function base64_decode(base64str, file) {
        // 버퍼 객체를 만든후, 인자 <=> (base64 스트링, 파일 경로)
        var bitmap = new Buffer(base64str, 'base64');
        // 버퍼의 파일을 쓰기
        fs.writeFileSync(file, bitmap);
    }

    try {
        console.time('/adopt/animalinfo');

        const {animalImage, animalGender, animalSpecies, animalAge,
            animalVaccinated, animalDisease, animalFind, animalIntro,
            adoptEnd, adoptCondition, animalWeight} = req.body;

        var filename = animalSpecies + animalAge; // 파일명 변수
        console.log('filename : ', filename);

        var filepath = 'filefile/' + filename + '.jpg'; // 파일경로 (서버에서의 상대경로)
        console.log('filepath : ', filepath);

        base64_decode(animalImage, filepath);  // 함수 실행

        const imageStream = fs.createReadStream(filepath);

        const params = { Bucket:BUCKET_NAME, Key:filename, Body:imageStream, ContentType: 'image' }
        const upload = new AWS.S3.ManagedUpload({ params });
        upload.promise()

        const postImageTestRows =
            await adoptModel.insertAdoptInfo(filepath, animalGender, animalSpecies, animalAge,
                animalVaccinated, animalDisease, animalFind, animalIntro,
                adoptEnd, adoptCondition, animalWeight);

        console.timeEnd('/adopt/animalinfo');
        res.json({
            isSuccess: true
        });

    } catch (err){
        logger.error(`postAdoptAnimalInfo DB Connection error\n: ${err.message}`);
        return res.status(500).send(`Error: ${err.message}`);
    }
};

 

💡 Comment

  • 원래 프론트에서 파일을 통째로 넘겨주기를 시도했으나, 현재 프론트에서 사용중인 Volley로는 어렵다고 한다. 따라서 base64 문자열을 넘기는 방법을 사용했는데, 이렇게 이미지를 전송할 때나 인증 관련된 정보를 전송할 때 종종 사용되는 방법이라고 한다.
  • 인코딩된 base64 문자열 또한 매우 길어서 그대로 DB에 저장하면 많은 용량이 사용될텐데, 따로 저장소를 생성하여 링크로만 접근하는 방법이 효율적이라는 생각을 했다. 실무에서는 파일들을 어떻게 저장할까 궁금하다.
  • 임시로 filename을 animalSpecies + animalAge로 설정했는데, 중복되는 경우 에러가 발생하는것을 확인했다. 이부분에 대한 예외처리가 필요하다.
  • putty는 안되는게 너무 많다..

 

 

참고

Node js와 AWS로 이미지 서버 만들기 (1) AWS 버킷 세팅하기 (tistory.com)

JAVA - 이미지 base64를 디코딩하여 파일 생성 후 DB에 디렉토리 저장 (tistory.com)

    nonneng.ee
    nonneng.ee

    티스토리툴바