[ 공모전 ] Binary Data : FileReader, Base64인코딩,Buffer

최문길·2024년 8월 3일
0

공모전

목록 보기
43/46
post-thumbnail

이전 포스팅에서 인코딩 깨짐 이슈로, Node.js 라이브러리를 통해서 해결했지만,
다른 팀원들과 상의한 결과 하나의 api router로 서버와 post ,delete , patch 통신을 최대한 간단하게 할 수 있게 했으면 좋겠다는 의견이 나왔다.


쉽게 말하면 Content-Typemultipart/form-data 가 아니라 application/json 타입이였으면 한다는 것이다.
그렇다면 file 객체를 string 타입의 데이터로 변환을 해야하는 상황인 것이다.

File객체의 실제 데이터

이전 포스팅에서 File Web APIs를 통해서 파일객체는 자바스크립트 내에서 파일데이터의 정보를 다룰 수 있는 객체라고 이야기 했는데,

그렇다면 어떻게 File객체의 실제 데이터 접근은 어떻게 할까이다.

FileReader로 접근

URL.createObjectURL vs FileReader 여기에 URL.createObjectURL 설명이 있기에 패스하겠다.

파일의 내용을( raw Data Buffer ) 읽고 조작하는 Web APIs이다.

FileReader 객체의 메소드는 5가지가 존재한다.

  1. FileReader.abort() : 파일 읽기를 중단.
  2. FileReader.readAsArrayBuffer() : 파일을 읽고, 그 결과값은 ArrayBuffer 형태를 저장 - 데이터를 일정한 크기로 잘라 서버로 보낼 때 사용
  3. FileReader.readAsBinaryString() : 파일을 읽고, 그 결과값 속성에 파일의 원시 이진 데이터 형태를 저장 - deprecated
  4. FileReader.readAsDataURL() : 파일을 읽고, 그 결과값 속성에 파일을 나타내는 URL을 저장
  5. FileReader.readAsText() : 파일을 읽고, 그 결과값은 파일의 텍스트 문자열 형태를 저장

FileReader의 이벤트 핸들러

FileReader는 비동기 매커니즘이기 때문에, 이벤트 핸들러를 등록하여 사용할 수 있다.
총 6개의 이벤트 핸들러가 있다.

  1. FileReader.onabort : 읽기 중단 시, 트리거 됨
  2. FileReader.onerror : 읽는 도중 오류 발생시, 트리거 됨
  3. FileReader.onload : 읽기 완료 시(성공만), 트리거 됨
  4. FileReader.onloadstart : 읽기 시작 시, 트리거 됨
  5. FileReader.onloadend : 읽기 완료 시( 성공, 실패 ) , 트리거됨
  6. FileReader.onprogress : 읽는 도중, 트리거 됨

지난 포스팅에서 getBase64 util 함수를 만들었었는데, 이것을 다시 한번 가져와 보자

function getBase64(file: File) {
  return new Promise<string>((resolve, reject) => {
    const reader = new FileReader();

    reader.readAsDataURL(file);
    reader.onload = () => resolve(<string>reader.result);
    reader.onerror = error => reject(error);
  });
}

FileReader 에서 readAsDataURL 메소드로 file을 파싱하여 실제 데이터를 url로 변환 하는 함수를 만들었는데, 다음과 같은 이유다.

출저 : mdn

base64인코딩 된 string data가 result속성에 담긴다.

그렇다 , 실제 파일의 데이터를 string으로 변환 하기 때문에 맨 상단에 써 놓았던, Content-Type: application/json 으로 보낼 수 가 있다.

물론 Blob으로 변환 할 수 있지만...

URL데이터를 Blob으로 변환 할 수 있지만, 우리는 Content-Type을 통일 하고 싶기 때문에...


DataURL

다시 돌아와서 Client 코드를 다시 작성하자면

// client
interface FieldValues {
  text: string
  file : FileList
}
//...생략
 const submitBase64 = async (value: FieldValues) => {
    const _file = await getBase64(value.file[0]);
   
   // _file타입은 string이므로 `application/json`
    const result = await axios.post("/api/binary/base64", { 
      ...value,
      file: _file,
    });
  };
//...생략

그리고 나서 api router의 터미널에서 확인해 보면

이렇게 json 형태로 받아와 진다.

{file: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAv0AAAJcCAIAA...' }

dataURL은 총 4가지 파트로 구성된다.
data:[<mediatype>][;base64],<data>

  1. 접두사 : data:
  2. 데이터의 타입을 가리키는 MIME타입
  3. 인코딩된 타입 - base64
  4. 실제 데이터 - , 이하

api router 로직

여기서 흐름을 놓칠 수가 있는데, api router로 보내는 이유는 mixed content error 때문이다.
그렇기에 api router 에서 formData를 합의한 Content-Type:application/json 으로 받아오고

그 다음 api router에서 formData를 만들어 다시 서버측에 보내줘야 우리가 원하는 Goal인 것이다.
따라서

// api router

function base64ToBuffer(base64String: string) {
  const base64Data = base64String.replace(/^data:image\/png;base64,/, "");
  return Buffer.from(base64Data, "base64"); // base64Data를 Buffer로 변환
}
export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse,
) {
  const { body } = req;
  const fileBuffer = base64ToBuffer(body.file);

  const formData = new FormData();
  formData.append("file", fileBuffer);
  formData.append("text", body.text);
  
	//...생략
}

Buffer는 Node.js 환경에서 Blob 객체가 제공되지 않는다 대신 Buffer를 통해서 인코딩 된 데이터를 바이너리 데이터로 변환 할 수 있다.

그 이후에 FormData에 추가 할 수 있다.

base64ToBuffer

Buffer.from(객체,인코딩:?) 의 메소드를 사용해서 base64데이터를 buffer 즉, 바이너리 데이터로 변환 할 수 있다.
이 메소드에는 2가지 인자가 필요 한데

  • 객체 : 문자열, 버퍼, 배열 또는 배열 버퍼 를 넣을 수 있다.

  • 인코딩 : 객체가 문자열이면 인코딩을 지정하는 사용된다. 선택적인 매개변수이며 default는 utf8 이다. 헷갈릴 수 있는데, 문자열의 인코딩이 무엇인지 적어두는 것이다.

따라서 나는 문자열인 base64Data 를 넣어줬고, base64로 인코딩된 문자열을 디코딩하여 Buffer로 만들라는 의미이다.


마무리

위의 변환하는 코드는 샘플로 내가 두고두고 볼 예제로 만들어 두었기에,
위와 유사한?(우리는 File[] 이거라 조금은 다르다) 코드로 작성하였더니 통신이 잘 되었다.

formData 통신을 위해서

  • Buffer
  • base64
  • Blob
  • File Web APis
  • FileReader Web Apis
  • formidable
  • bodyParser
  • rawBody
  • req.on
  • multipart/form-data
  • HTTP Protocol

이렇게 많은 것을 알아 보았다.
그 중에서 node.js 쪽으로도 내 web 생태계의 영역이 확장 되어서 뿌듯하다.

마무리 2

내가 맡은 구현에 대한 공모전 작성이 끝났다. 2024년 6월 19일 ~ 2024년 8월 3일

총 43편의 포스팅을 했는데,
요번 프로젝트는 서울시에서 하는 공모전이고, 실제 서버쪽과 통신하는 귀중한 시간이기도 했고, app router 로 넘어가는 과도기 적인 상태에서의 프로젝트였던 것 같다.

이제 이력서 넣어보자....

0개의 댓글

관련 채용 정보