• Company
  • 6주 완성 MVPAI 운영 전환 플랜리트머스 팀 케어IT 비즈니스 빌드 프로그램Figma 기반 서비스 구현레퍼런스 앱 구현
  • Portfolio
  • Blog
문의하기

대표: 김응진이메일 : minsuk@cigro.io

사업자 등록번호 : 119-87-09475

주소 : 서울 서초구 효령로 304, 국제전자센터 B1 포티에 C동

Copyright ⓒ Cigro. All rights reserved. Seoul south korea

버블에서 이미지 압축 및 다운로드 구현하기
2025.01.24

버블에서 이미지 압축 및 다운로드 구현하기

기술 인사이트

버블에서 이미지 압축 및 다운로드 구현하기

 

안녕하세요. 리트머스입니다.

이번 포스팅에서는 여러개의 이미지를 압축하여 다운로드하는 기능에 대해서 알아보려고 합니다.

웹에서 이미지 파일은 가장 흔히 사용되고 다운로드되는 파일 형식 중 하나로, 이를 제대로 처리하는것은 사용자 경험을 향상시킨다는 점에서 중요합니다. 그러나 여러 이미지를 한 번에 다운로드하거나 압축 파일로 제공하려고 할 때, 예상치 못한 기술적 제약이 발생할 수 있습니다.

이 글에서는 Bubble.io에서 여러 이미지를 zip 파일로 다운로드하는 기능을 구현하는 과정을 자세히 다룹니다. 특히, 이미지 다운로드 과정에서 흔히 발생하는 CORS(Cross-Origin Resource Sharing) 오류와 그 원인을 파악하고, 이를 해결하기 위한 구체적인 방법을 설명합니다. 또한, Base64 변환 및 JSZip을 사용하여 이미지 데이터를 효율적으로 압축하고, 최종적으로 사용자가 간편하게 다운로드할 수 있도록 처리하는 방안을 제시합니다.

글을 다 읽고 나면, 다음과 같은 내용을 알 수 있습니다:

  • 여러 이미지를 zip 파일로 다운로드하는 기능의 구체적인 구현 방법.
  • 압축 다운로드 플러그인을 써도 다운로드가 잘 안 되는 이유
  • 버블의 보안 방식과 브라우저 정책 이해

 

CORS 오류로 인한 이미지 다운로드 문제와 해결 방법

Bubble.io에서 이미지를 처리하는 과정 중, 여러 이미지를 압축하여 다운로드하려고 할 때 CORS(Cross-Origin Resource Sharing) 오류가 발생하는 경우가 있습니다. 이 문제는 Bubble에서 제공하는 이미지 URL 구조와 브라우저 정책에서 기인합니다. 본 글에서는 이러한 오류의 원인과 이를 해결하는 방법을 설명하고자 합니다.

1. 문제 원인: Bubble 이미지 URL의 구조

Bubble.io의 이미지 URL은 다음과 같이 구성됩니다:

https://xxxxxxxx.cdn.bubble.io/xxxxxxxx/image_name.jpg

처음 URL만 보면 일반적인 이미지 파일처럼 보이지만, 뒤에 붙는 파라미터가 문제를 야기합니다:

?_gl=1icn2dh_gcl_au*MTY0NjQzMTkzNi4xNzM0NjAzNzI4…

이 파라미터는 Bubble이 이미지 요청 시 토큰을 포함하여 이미지를 보호하기 위해 사용하는 메커니즘입니다. 따라서 외부 애플리케이션이나 API를 통해 이미지를 직접 요청하면 브라우저의 CORS 정책에 의해 차단됩니다.

CORS란? CORS는 웹 브라우저가 도메인 간 리소스 요청을 제어하는 보안 기능입니다. Bubble 이미지 URL에 포함된 토큰이 올바르지 않으면 요청이 차단됩니다.

 

2. 직접 접근

Bubble에서 제공하는 이미지 URL을 그대로 주소창에 입력하면 이미지를 정상적으로 열 수 있습니다. 이는 브라우저가 Bubble 서버에서 직접 이미지를 로드하기 때문입니다. 이를 풀어서 설명하면 다음과 같습니다.

  • Bubble에서 제공하는 URL은 Bubble 서버의 CDN(Content Delivery Network)에서 이미지를 제공하는 주소입니다.
  • 사용자가 Bubble 이미지 URL을 주소창에 입력하면, 브라우저는 Bubble 서버에 직접 요청을 보냅니다.
  • 이 요청은 사용자의 브라우저에서 Bubble 서버로 보내지며, 동일한 도메인 간의 요청으로 간주됩니다.
  • CORS 정책은 도메인 간 요청(Cross-Origin Request)을 제어하는 정책이므로, 동일 도메인 내에서의 요청은 차단되지 않습니다.

그러나 다른 도메인, 예를 들어 https://litmers.com과 같은 클라이언트 사이드 애플리케이션에서 API를 통해 이미지를 요청하면 CORS 오류가 발생합니다. 요청 도메인(https://litmers.com)과 이미지의 도메인(https://xxxxxxxx.cdn.bubble.io)이 다르기 때문입니다.

 

3. 해결 방법: 서버 사이드에서 이미지 처리

CORS 정책 문제로 인해 클라이언트 사이드에서는 Bubble.io의 이미지를 직접 다운로드하거나 변환하는 것이 불가능합니다. 따라서 다음과 같은 방식으로 서버 사이드에서 문제를 해결해야 합니다:

  1. Bubble 서버의 이미지 데이터를 Base64로 변환
    • 서버 사이드 코드에서 Bubble 이미지 URL에 접근하여 이미지를 요청합니다.
    • 응답 받은 이미지를 Base64 형식으로 변환합니다.
  2. 여러 이미지를 압축 파일로 묶기
    • 변환된 Base64 데이터를 압축 도구를 사용하여 ZIP 파일로 묶습니다.
  3. 사용자에게 다운로드 제공
    • 최종적으로 생성된 ZIP 파일을 클라이언트가 다운로드할 수 있도록 API로 제공합니다.

 

4. 구현 예시

다음은 이미지 url을 서버 사이드에서 base64로 변환해서 다운로드 하는 구현 예시입니다.

1. 이미지 url을 서버 사이드에서 base64로 변환

버블에서 이미지 압축 및 다운로드 구현하기

버블에서 이미지 압축 및 다운로드 구현하기

버블에서 이미지 압축 및 다운로드 구현하기

  • 서버 사이드 (백앤드 워크플로우)에서 base64로 인코딩 하는 방법
  • 백앤드 워크플로우에서 인코딩한 결과값을 클라이언트 사이드(일반 워크플로우)에서 받아오는 방법 - API Connector를 통해 콜합니다.

↗︎ endcoded in base64 에 대한 설명 바로가기

 

2. 압축 후 다운로드

Base64 이미지 데이터를 JavaScript를 사용해 ZIP 파일로 압축하고 다운로드하는 스크립트입니다.

버블에서 이미지 압축 및 다운로드 구현하기

// Base64 이미지 데이터 리스트

const base64Images = ["XXXXX.....];

// JSZip 인스턴스 생성

const zip = new JSZip();

// Base64 이미지 데이터를 zip 파일에 추가 base64Images.forEach((base64, index) => {

const fileName = `image_${index + 1}.png`; // 파일 이름 생성

zip.file(fileName, base64.split(",")[1], { base64: true }); // Base64 데이터에서 prefix 제거 후 추가

});

// 압축 파일 생성 및 다운로드

zip.generateAsync({ type: "blob" }).then(function (content) {

const a = document.createElement("a");

a.href = URL.createObjectURL(content);

a.download = "images.zip"; // 압축 파일 이름 a.click();

});

위 스크립트에 대한 설명은 다음과 같습니다.

 

전체 코드의 흐름

  1. Base64 데이터를 배열에 저장합니다.
  2. JSZip 객체를 생성해 ZIP 파일 작업을 시작합니다.
  3. 각 Base64 데이터를 순회하며 ZIP 파일에 추가합니다.
  4. ZIP 파일을 Blob으로 생성하고 임시 URL을 통해 다운로드 링크를 만들어 사용자가 ZIP 파일을 다운로드할 수 있게 합니다.

1. Base64 이미지 데이터 리스트 정의

const base64Images = ["long_base64_information_string_0","long_base64_information_string_1" ... ];

  • 목적: Base64 형식으로 인코딩된 이미지 데이터를 배열 형태로 저장합니다.
  • 설명: Base64 데이터는 이미지 파일을 텍스트 형식으로 표현한 데이터입니다. 여기서 base64Images는 여러 이미지를 저장하는 배열입니다. 각각의 요소는 이미지 하나에 해당합니다.

2. JSZip 인스턴스 생성

const zip = new JSZip();

  • 목적: JSZip 라이브러리를 이용해 ZIP 파일을 생성하기 위한 인스턴스를 만듭니다.
  • 설명: JSZip은 클라이언트 사이드에서 ZIP 파일을 생성할 수 있게 해주는 JavaScript 라이브러리입니다. new JSZip()을 호출하면 ZIP 파일 생성 작업을 관리할 수 있는 객체가 생성됩니다.

3. Base64 데이터를 ZIP 파일에 추가

base64Images.forEach((base64, index) => {

const fileName = `image_${index + 1}.png`; // 파일 이름 설정

zip.file(fileName, base64, { base64: true }); // Base64 데이터 추가

});

  • 목적: Base64 데이터를 순회하며 ZIP 파일에 추가합니다.
  • 세부 설명:
    • base64Images.forEach: 배열의 각 요소(Base64 데이터)를 순회합니다.
    • index: 현재 순회 중인 요소의 인덱스입니다.
    • const fileName = image_${index + 1}.png;: ZIP 파일 내에서 사용할 이미지 파일의 이름을 동적으로 생성합니다. 예: image_1.png, image_2.png.
    • zip.file(fileName, base64, { base64: true });: JSZip 객체에 파일을 추가합니다.
      • fileName: 파일 이름.
      • base64: 파일 데이터(Base64 형식).
      • { base64: true }: 데이터가 Base64 형식임을 명시합니다.

4. 압축 파일 생성 및 다운로드

zip.generateAsync({ type: "blob" }).then(function (content) {

const a = document.createElement("a");

a.href = URL.createObjectURL(content);

a.download = "images.zip"; // 압축 파일 이름

a.click();

});

  • 목적: ZIP 파일을 생성하고 브라우저를 통해 다운로드합니다.
  • 세부 설명:
    • zip.generateAsync({ type: "blob" }):
      • ZIP 파일을 비동기로 생성합니다.
      • type: "blob": 생성된 ZIP 파일 데이터를 Blob(Binary Large Object) 형식으로 반환합니다.
    • .then(function (content) { ... }):
      • ZIP 파일 생성 작업이 완료되면, 반환된 Blob 데이터를 처리합니다.
    • document.createElement("a"):
      • 다운로드 링크를 생성합니다. <a> 태그는 파일 다운로드를 트리거하는 데 자주 사용됩니다.
    • a.href = URL.createObjectURL(content);:
      • Blob 데이터를 임시 URL로 변환해 링크에 연결합니다.
    • a.download = "images.zip";:
      • 다운로드되는 ZIP 파일의 이름을 지정합니다.
    • a.click();:
      • 생성한 링크를 클릭해 다운로드를 시작합니다.

참고 라이브러리

↗︎ JSZip 공식 문서

참고 버블 문서

↗︎ Bubble Docs

 

결론

Bubble.io의 이미지 URL과 CORS 정책 때문에 클라이언트 사이드에서 직접 이미지를 처리하는 것은 불가능합니다. 그러나 서버 사이드에서 이미지 데이터를 Base64로 변환하고 이를 압축하여 제공하면 이러한 문제를 해결할 수 있습니다. 위 과정을 통해 사용자는 여러 이미지를 손쉽게 다운로드할 수 있습니다.

Bubble.io와 같은 플랫폼의 보안 메커니즘을 이해하고, 이에 맞는 서버 사이드 처리 방식을 구현하는 것은 사용자 경험을 향상시키는 데 중요한 요소입니다.

 

 

 

🔎 버블을 더 똑똑하게 활용하고 싶다면?

↗︎ 더 알아보기


연관 아티클

외주 개발 견적 줄이는 방법과 실제 사례 (2025 최신)

외주 개발 견적 줄이는 방법과 실제 사례 (2025 최신)

버블 데이터베이스 트리거: 데이터 관리 자동화 및 최적화

버블 데이터베이스 트리거: 데이터 관리 자동화 및 최적화

리트머스가 동아시아 최초 골드 에이전시가 되었습니다!

리트머스가 동아시아 최초 골드 에이전시가 되었습니다!

노코드란? 정의부터 성공사례까지 총정리 (2025 최신)

노코드란? 정의부터 성공사례까지 총정리 (2025 최신)

버블 AMA 요약 정리: 버블 AI는 어떻게 앱 제작 방식을 바꾸는가

버블 AMA 요약 정리: 버블 AI는 어떻게 앱 제작 방식을 바꾸는가

노코드란?: 노코드에 대한 모든 것

노코드란?: 노코드에 대한 모든 것

노코드(no code)란? 노코드 개발의 장단점

노코드(no code)란? 노코드 개발의 장단점

[2025 최신] 버블에서 리피팅 그룹 각 셀마다 워크플로우를 실행하고 싶을 때 : 플러그인 오케스트라(Orchestra)

[2025 최신] 버블에서 리피팅 그룹 각 셀마다 워크플로우를 실행하고 싶을 때 : 플러그인 오케스트라(Orchestra)

리트머스에 프로젝트를 문의해보세요!

빠르고 확실한 결과물,리트머스가 함께합니다

문의하기