토이 프로젝트를 진행하는 중 바이너리 데이터를 변환해 사용하다가 제대로 되지 않은 적이 있어 쓰는 글 (문제 해결)
이번 프로젝트에서는 Google Places API에서 식당 사진을 받아온다.
구글에 photo reference와 함께 사진 요청을 해서 로그를 찍어보면,
아래와 같은 형식의 바이너리 데이터를 확인할 수 있다.
이 데이터는 사람이 읽을 수 없는 Raw Binaray Data 형태로서, 이미지 파일의 바이트 스트림이라 브라우저나 클라이언트에서 변환을 해줘야 한다!
어떤 것들이 있는지 확인해보자!
위의 코드는 내가 프로젝트에 적용한 함수이다.
여기서 API get 요청을 할 때 responseType을 "blob"으로 명시해주어 받아왔다.
이 blob을 사용한 옵션은 axios나 브라우저의 XMLHttpRequest를 통해 서버로부터 데이터 요청 시,
데이터를 Blob 객체 형태로 받을 수 있는 옵션이다!
이 설정은 이미지, 비디오, 오디오, PDF 등 아까 보여줬던 바이너리 데이터 형식을 효율적으로 처리할 수 있음 :)
보통 HTTP 요청으로 서버에서 데이터를 가져올 때, 데이터는 JSON이나 텍스트 형태의 문자열을 반환한다.
그러나!
이미지나 파일 같은 바이너리 데이터를 다룰 때는 데이터를 텍스트로 변환하는 과정에서 데이터 손실이 발생할 수 있다.
그래서 responseType: 'blob'을 사용해 데이터를 Blob 형태로 받아와 손실 없이 가져올 수 있다는 말임!
그럼 코드를 이어서 확인해보자.
responseType: 'blob'을 사용해 가져온 데이터는 Blob 객체이다.
나는 이 객체를 이용해 화면에 뿌려주고 싶기 때문에 Blob 형태가 아닌 URL 형태를 원한다.
이 URL.createObjectURL()은 브라우저에서 제공하는 API로,
Blob이나 File 객체에 대한 임시 URL을 생성하게 해준다!
(이미지, 비디오, 오디오, 파일 다운로드 등에 활용)
- 임시 URL 생성
: 반환된 URL은 실제 파일 경로가 아닌 가상 경로이다.
(브라우저 메모리에 이 URL이 존재해 페이지를 새로 고침하거나 닫으면 사용할 수 X : 브라우저 세션동안만 유효)
-> URL이 필요하지 않으면 URL.revokeObjectURL(blobURL)로 명시적 해제를 해주며 메모리 관리를 해줘야 함!
- 효율적인 데이터 접근
: 클라이언트 메모리 내에서 직접 참조하여 빠르게 처리
- 주요 사용 사례
: 이미지는 img 태그, 비디오/오디오 파일은 video/audio 태그에 연결한다
그래서 상단의 적용 코드에서,
URL.createObjectURL(response.data)로 Blob URL을 생성하여 바로 img 태그의 src에 적용할 수 있게 한 것이다!
이 Blob URL이 어떤 형태로 생겼는지 로그를 찍어보면
로컬 환경 예시:배포 환경 예시:
위와 같은 형식인 걸 확인할 수가 있다!
ArrayBuffer는 자바스크립트에서 바이너리 데이터를 저장하고 처리하기 위한 기본적인 객체이다.
(데이터를 이미지, 오디오, 비디오 등으로 다룰 수 있음)
API 요청을 할 때, responseType을 'arraybuffer'로 지정해준다.
(ArrayBuffer 형태로 받아오기)
그 다음, new Blob([response.data], { type: 'image/jpeg'})을 사용해
Blob 객체로 변환을 한다.
new Blob을 사용할 때, 첫 번째 인자는 데이터 배열이고 두 번째는 해당 데이터 타입을 설정해준다.
(jpeg가 아닌 다른 이미지 형식이라면, 다른 걸로 명시해줘도 됨)
이렇게 blob 객체로 변환해준 뒤,
URL.createObjectURL()로 임시 URL를 받아내 사용할 수가 있다!
맨 처음의 첫 번째 방법에서는 responseType이 blob이었는데,
왜 여기서는 arraybuffer일까?
: Blob과의 호환성 때문이다.
이번 방법은 new Blob을 활용해 Blob 객체로 변환하는 방법이다.
ArrayBuffer는 Blob 객체로 변환하여 사용할 수 있기에, new Blob을 사용해 ArrayBuffer를 Blob 객체로 변환해 사용하는 것이다.
나는 처음에 이 방법을 먼저 사용했었는데,
API 요청에서 responseType: 'arraybuffer' 명시를 해주지 않았다.
그 상태에서 그냥 바이너리 데이터를 new Blob으로 감싸 blob 객체로 변환하려 했던 것이다.
그러니 그냥 바이너리 데이터를 blob 객체로 변환하는 것이 안 돼서 화면에 사진이 뜨지 않았던 것!
먼저 blob 형식의 데이터를 base64로 변환하는 함수를 만들어준다.
그 다음, API 요청 함수에서 바이너리 객체를 blob으로 변환 한 후 상단 함수의 인자에 넣어준다.
일반적으로 첫 번째 방법인 responseType: 'blob'이 간단하고 효율적이므로,
이 방법으로 바이너리 데이터를 blob으로 받아와 URL로 변환해 사용하는 것이 좋겠다!