개발자
류준열
TinyMCE 에디터에서 이미지를 base64로 저장하면서 생긴 문제 해결
문제 상황
글 발행 기능을 만들었는데, 이미지 업로드시에 요청사이즈가 너무 커서 서버에서 튕겨내는 상황이 발생했다.
분석해보니 프론트에서 사용하는 TinyMCE가 이미지를 base64로 저장하면서 DB사이즈를 초과하는 이슈였다.
해결과정
TinyMCE 에디터의 기능을 유지해야 하기 때문에 서버에서 대용량 이미지를 처리 할 수 있어야 했다.
조금 검색해보니 서버에서 일단 base64를 받고 파싱해서 s3에 업로드 후 base64랑 교체하는 방식으로 해결하고 있어서 따라했다.
-
먼저 base64를 받기 위해 Express body parser 크기 제한을 50MB로 증가시켰다.
-
그 후 html에서 base64 를 찾아내 s3에 업로드하고, 원본 이미지를 s3에 저장한 이미지로 수정하였다.
export async function replaceBase64ImagesWithS3Urls(
htmlContent: string
): Promise<string> {
try {
// base64 이미지 패턴 정규식
const base64ImageRegex =
/<img[^>]*src="(data:image\/[^;]+;base64,[^"]+)"[^>]*>/g;
let updatedContent = htmlContent;
const matches = [...htmlContent.matchAll(base64ImageRegex)];
if (matches.length === 0) {
return htmlContent; // base64 이미지가 없으면 원본 반환
}
console.log(`Found ${matches.length} base64 images to upload`);
// 각 base64 이미지를 S3에 업로드
for (const match of matches) {
const fullImgTag = match[0];
const base64Data = match[1];
try {
// S3에 업로드
const s3Url = await uploadBase64ToS3(base64Data);
// 원본 img 태그에서 base64 src를 S3 URL로 대체
const updatedImgTag = fullImgTag.replace(base64Data, s3Url);
// 콘텐츠에서 원본 태그를 업데이트된 태그로 대체
updatedContent = updatedContent.replace(fullImgTag, updatedImgTag);
console.log(
`Successfully uploaded and replaced base64 image with S3 URL: ${s3Url}`
);
} catch (error) {
console.error("Error uploading individual image:", error);
// 개별 이미지 업로드 실패 시 해당 이미지는 그대로 유지
}
}
return updatedContent;
} catch (error) {
console.error("Error processing base64 images:", error);
// 전체 처리 실패 시 원본 콘텐츠 반환
return htmlContent;
}
}
프론트에서부터의 상황을 도식화 하면 다음과 같다.
before
<!-- TinyMCE에서 생성된 HTML --> <h3>제목</h3> <p>내용</p> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABNQAAAKWCAYAAACBCMTUAAABWWlDQ1BJQ0MgUHJvZmlsZQAAKJF1kD9Lw1AUxU9qIUFbKOJQQSFrIUqpdnSoH.....(매우 긴 base64 문자열)" />
after
<!-- S3 URL로 대체된 HTML --> <h3>제목</h3> <p>내용</p> <img src="https://aneun-dongne.s3.ap-northeast-2.amazonaws.com/posts/images/86910582-8b1e-446f-add8-c84a4abc40b6.png" />
좋아진 것들
- DB에서 url만 저장하면서 부담 감소(기존 수십KB에서 100B내외)
- s3 CDN을 통한 이미지 로딩 속도 감소