새소식

개발일기/TIL

Base64 인코딩과 이미지업로드 회고....

  • -

때는 base64 와 인코딩을 잘 모르던 시절...

나는 React로 이미지 업로드를 구현했다.

여러장의 이미지를 받아야하는 플랫폼 특성상 어떻게 이미지를 여러장 받아서 서버에 넘겨줄 수 있을까 고민을 했다.

서버의 부하를 막고, 간단하게 이미지를 프리뷰해줄수 있게하기 위해 결론적으로 생각 해 낸 방법은 다음과 같았다.

 

1. 사용자가 이미지를 업로드한다.

2. 이미지 리사이즈 로직을 돌아 서버에 해당 이미지를 전달해준다.

3. 전달해준 이미지에 대한 응답값으로 서버에서는 url을 돌려준다.

4. 돌려준 url을 이미지 프리뷰로 띄워준다.

5. 사용자가 작성폼 작성을 마치면 작성한 글과 함께 돌려받은 이미지 url을 함께 전송해준다.

위 해답에 도달하기 전에 이미지파일 업로드는 처음이라서 정말 많은 고생을 했던 기억이 있다...

사실 벨로그처럼 마크업 라이브러리를 공부하고 사용하면 참 편할 것같았지만, 간단하고 빠른(그리고 쉬운 )업로드를 위해 모든 팀원이 같이 머리를 싸맸었다.

 

 

오늘 기술면접 준비를 하며 base64 인코딩에 대해 공부했고, 추가적으로 서버에 이미지를 보낼 때 필요한 개념들에 대해 알아봤다. 이에 따라서 과거 코드(왜 저렇게 했을까..)에 대해 다시 곱씹어보고 개선방안을 찾아 볼 수 있게 되었다. 

 

 

 

우선,  Base64 인코딩이란 무엇인가?

 

인코딩은 파일에 저장된 정보의 형태나 형식을 데이터 표준화, 보안, 처리 속도 향상, 저장 공간 절약 등을 위해서 다른 형태로 변환하는 처리 혹은 그 방식이다. 주로 이메일 등의 전송이나 동영상과 이미지에서 많이 사용된다.

 

따라서 base64 인코딩  

이진데이터(8비트)를 아스키 문자로만 이루어진 텍스트로 변환시키는 인코딩이다.

이는 문자 코드에 영향을 받지 않는 아스키 문자로들만 이루어진 일련의 문자열로 바꾸는 인코딩 방식을 가르킨다.

어떤 문자와 기호를 쓰냐에 따라 많은 종류가 있지만, 가장 기본적인것은 A-Z, a-z, 0-9를 사용해서 62개이고 나머지 2개를 어떤 기호로 사용할 것이냐에 따라 차이가 있다.

 

 

 

🤷🏻‍♀️Base64를 사용하면 데이터의 크기가 늘어나는데???

 

Base64로 인코딩 하게 되면 6bit 당 2bit의 오버헤드가 발생하여 전송하는 데이터의 크기가 늘어나게 된다.

또한 인코딩과 디코딩에 추가 CPU 연산까지 필요할 것이다.

 

그런데도 사용하는 이유가 있을 것이다.

그 이유는 '통신과정에서 바이너리 데이터의 손실을 막기 위해서'이다.

 

 

ASCII 문자는 대표적으로 다음과 같은 문제를 발생시킬 수 있다.

  • ASCII는 7bit 인코딩인데 나머지 1bit를 처리하는 방식이 시스템별로 다르다.
  • 일부 제어 문자의 경우 시스템 별로 다른 코드값을 가진다.

 

 

위와 같은 문제로 아스키는 시스템간 데이터를 전달하기에 안전하지 않다.

Base64는 ASCII 중 제어문자와 일부 특수문자를 제외한 64개의 안전한 출력문자만 사용한다.

 

즉, 전송해야할 데이터의 크기가 늘어남에도 Base64를 사용하는 이유는, HTML 또는 Email과 같이 문자를 위한 media에 Binary Data를 포함해야 될 필요가 있을 때, 포함된 Binary Data가 시스템 독립적으로 동일하게 전송 또는 저장되는 것을 보장하기 위해서 사용한다.

 

 

 

서버에 이미지를 보내기 위한 여러.. 개념...

 

1. XMLHttpRequest

XHR 객체는 서버와 상호 작용시에 사용한다.

XHR을 이용하면 페이지의 새로고침 없이 데이터를 요청하거나 받아올 수 있다. 따라서 이를 활용하면 사용자의 작업을 방해하지 않고 페이지의 일부를 업데이트 할 수 있다.

 

이는 AJAX 프로그래밍에 많이 사용된다

 

XML 뿐만 아니라 모든데이터를 가져올 수 있다.

let xmlHttp = new XMLHttpRequest()

생성자 함수 new를 사용해서 XMLHttpRequest 객체를 생성한다.

 

XMLHttpRequest.open(method, url, [async])

요청을 초기화 한다.

  • method : get, post 와 같은 HTTP request method
  • url : 요청을 보낼 url
  • async : 비동기로 동작할 것인지 (default 는 ture) multipart 속성을 설정했을 때는 반드시 이 값도 ture여야한다.

 

XMLHttpRequest.send([body]) 

요청을 전송한다.

 

서버로 요청을 전송한다. 요청이 비동기인경우에는 요청을 전송하는 즉시 반환한다.

(동기인 경우에는 서버로부터 응답이 도착할 때까지 반환되지 않는다.)

 

request body를 지정하는 파라미터를 (필요한경우) 받는다. -> Put 같은 경우

바이너리 컨텐츠를 전송할 때 최적의 방법은 TypedArray, DataView, Blob객체를 함께 사용하는 것.

 

XMLHttpRequest.setRequestHeader(header, value)

http요청 헤더의 값을 설정한다.

send()보다 먼저, open()보다 뒤에서 호출해야한다.

헤더 설정하지 않으면 send()가 호출 될 때 Accept 헤어가 */* 와 함께 전송 된다.

  • header : 설정할 헤더 이름
  • value :  body에 설정 될 값

https://developer.mozilla.org/ko/docs/Web/API/XMLHttpRequest

 

XMLHttpRequest - Web API | MDN

XMLHttpRequest (XHR) 객체는 서버와 상호작용할 때 사용합니다. XHR을 사용하면 페이지의 새로고침 없이도 URL에서 데이터를 가져올 수 있습니다. 이를 활용하면 사용자의 작업을 방해하지 않고 페이

developer.mozilla.org

 

2. AJAX(Asynchronous JavaScript And XML)

 

앞서 기술한 XMLHttpRequest를 이용하기 때문에 AJAX 는 비동기성이다. (따라서 페이지 전체 업데이트 하지 않고 일부분만 변경가능)

 

AJAX는 JSON, XML, HTML, 텍스트 등 다양한 포멧을 주고받을 수 있다. 

 

https://developer.mozilla.org/ko/docs/Web/Guide/AJAX/Getting_Started

 

Ajax 시작하기 - 웹 개발자 안내서 | MDN

본 문서는 AJAX의 기본을 익힐수 있도록 해주며, 두 가지 간단한 훈련용 예제를 제공합니다.

developer.mozilla.org

 

 

앞서 언급한 프로젝트에서는 axios를 사용하여 간단하게 서버에 요청을 했다.

MDN을 읽고 위 과정을 이해하면서 너무 쉽게쉽게 생각했고 모르면 일단은 급하니까 모르는대로 넘어간게 참 아쉬웠다...

axio에서 XHR 객체를 생성해서 이 데이터를 바디에 담아서 서버로 전송해주는 과정을 알아서 대신 해주고 있었는데,!!!!!! 이것도 모르고 그냥 왜 안될까... 이렇게 하면 되겠지? 했던 나의 과거를 반성 해본다...

 

 

프로젝트에서는 이미지를 Formdata를 통해 보내주고 있다.

그럼 FormData에 대해 좀 더 자세히...

 

FormData

FormData란 HTML 단이 아닌 자바스크립트 단에서 폼 데이터를 다루는 객체이다.

제출은 AJAX를 통해 서버에 제출하게 된다.

HTML <form> 태그 전송 = FormData

 

이미지를 전송하거나 새로고침 없이 폼데이터를 전송하고 싶을 때 사용한다.

 

FormData.append(name,value,[filename])

append를 사용하여 key, value 쌍을 FormData 객체에 추가한다.

값은 무조건 문자열로 자동 변환 된다. 객체나 배열 같은 복잡한 데이터는 넣을 수 없다.

  • name : value에 포함되는 데이터 필드의 이름
  • value : 필드의 값
  • filename : Blob(?????) 또는 File이 value로 전달 될 때 서버에 알려주는 파일 이름

 

Blob이란???

Binary Large Object로, 파일류의 미가공 데이터를 나타낸다.

 

 

 

다시 돌아와서 FormData 값 콘솔로 출력해보기..!

사실 프로젝트를 진행하면서 FormData를 콘솔에 그냥 찍을 수 없다는 것을 알고 진짜 엄청엄청 놀랐었다..

FormData 객체를 단순한 객체로 생각해서 이르게 된 정말 얕은 논리를 가졌기 때문에...

사실 FormData는 단순한 객체가 아니며 XMLHttpRequest 전손을 위하여 설계된 특수한 객체 형태기 때문이다.

그래서 간단하게 문자열화 할 수 없어 console.log()가 불가능 한 것 !!!

 

 

💁🏻‍♀️FormData의 값을 알아보려면?

-> for문 순회로 알아보기 ! 

let formData = new FormData();
formData.append('key1', 'value1');
formData.append('key2', 'value2');
 
// 폼 객체 key 값을 순회.
let keys = formData.keys();
for (const pair of keys) {
    console.log(pair); 
}
 
// 폼 객체 values 값을 순회.
let values = formData.values();
for (const pair of values) {
    console.log(pair); 
}
 
// 폼 객체 key 와 value 값을 순회.
let entries = formData.entries();
for (const pair of entries) {
    console.log(pair[0]+ ', ' + pair[1]); 
}

출처 : https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-FormData-%EC%A0%95%EB%A6%AC-fetch-api

 

[JS] 📚 FormData 사용법 & 응용 총정리 (+ fetch 전송하기)

FormData API 보통 서버에 데이터를 전송하기 위해서는 HTML5 의 폼 태그를 사용해 다음과 같이 메뉴를 구성하여 제출 해본 기억들이 있을 것이다. 아이디 비밀번호 성별 남자 여자 응시분야 영어 수

inpa.tistory.com

 

되돌아보며...

프로젝트 구현한 것을 되돌아보면 단순 crud를 구현했다 싶은 순간도 분명있었다.

이미지를 다루긴 했지만 내가 과연 잘 한건가 싶은 의문이 들기도 했다. 

프로젝트를 하면서는 시간에 쫓겨 구글링을 하고, 해결 코드를 그대로 따라치고 얕은 이해에서만 멈추었지만 Base64 인코딩에서 부터 뻗쳐나온 생각에 그 때, 과거의 나에게 안주하지 않아서 정말 다행인 순간이다.

앞으로는 절대... 단순 구글링과 코드 긁어오는 짓은 절대 안할것이다. 3-40분을 투자하더라도 조금이라도 지식을 쌓아야지.. 흑흑

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.