우당탕탕 기술블로그
[React] 이미지 등록 후 서버 요청 시 413 에러 발생, 이미지 압축하기 본문
✏️ 문제 상황
회원정보 수정 페이지 내에서 프로필에 고화질 이미지를 등록하고 수정을 서버에 요청한다면 413 Payload Too Large 에러 발생
여기서 HTTP 상태코드인 413 에러는 요청 엔터티가 서버에 의해 정의된 제한보다 크다는 것을 의미한다.
🧐 문제 원인
1MB 정도의 이미지 파일을 서버에 보낸다면 413 에러를 뱉어내서 수정을 할 수 없게 된다.
const handleFileSelect = (e: ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (file) {
const reader = new FileReader();
reader.onload = () => {
setImageSrc(reader.result as string);
};
reader.readAsDataURL(file);
}
}
...
const handleSubmit = useCallback(
async (event: MouseEvent<HTMLButtonElement>) => {
event.preventDefault();
if (isValid && window.confirm('수정하시겠습니까?')) {
try {
const formData = new FormData();
if (imageFile) {
formData.append('user_img', imageFile as File);
}
formData.append('user_name', inputName.trim());
formData.append('user_introduction', userInfo.user_introduction);
formData.append('user_career_goal', userInfo.user_career_goal);
formData.append('user_stacks', JSON.stringify(stackList || []));
await updateUserProfile(formData);
...
<div className={styles.imageContainer}>
<img
className={styles.image}
src={imageSrc}
alt={user?.user_name}
onClick={handleImageChange}
/>
<input
type="file"
accept="image/*"
onChange={handleFileSelect}
className={styles.fileInput}
ref={fileInputRef}
/>
...
😊 해결 방안
백엔드에서 Express 를 통해 이미지의 용량 제한을 푸는 것이 일반적이겠지만 백엔드 팀원이 1분이라 빨리 프로젝트를 진행해야하는 만큼, 프로필 이미지를 페이지내에 150px로 작은 사이즈로 띄우는 만큼 간단하게 프론트 쪽에서 미리 이미지 압축기능을 처리하기로 했다.
이미지 압축을 위한 라이브러리를 설치했다.
npm i browser-image-compression
우선 option 객체를 지정하여 이미지 압축에 필요한 옵션을 지정해줄 수 있다. 여기서 maxSizeMB 혹은 maxWidthOrHeight 값 중 하나는 필수로 지정해주어야 한다.
const options: Options = {
maxSizeMB: number,
maxWidthOrHeight: number,
onProgress: Function,
useWebWorker: boolean,
libURL: string,
preserveExif: boolean,
signal: AbortSignal,
maxIteration: number,
exifOrientation: number,
fileType: string,
initialQuality: number,
alwaysKeepResolution: boolean
}
압축이 필요한 이미지 파일 객체와 지정한 option을 인수로 추가해 이미지 압축을 진행하면 간단하게 이미지 압축이 완료된다.
const compressedBlob = await imageCompression(file, options);
마지막으로, form-data로 서버에 보내게 되는데 이미지를 file 객체로 보내달라고 요청해주셨다.
해당 라이브러리는 이미지 file 객체를 받아 압축을 진행하고 blob 객체를 반환하기 때문에 별도의 파일 객체 변환과정을 진행했다.
import imageCompression from 'browser-image-compression';
...
const handleFileSelect = async (e: ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
const options = {
maxSizeMB: 1,
maxWidthOrHeight: 1920,
useWebWorker: true
}
if (file) {
try {
// 이미지 압축
const compressedBlob = await imageCompression(file, options);
// Blob을 File 객체로 변환
const convertedFile = new File([compressedBlob], file.name, {
type: file.type,
lastModified: Date.now()
});
setImageFile(convertedFile);
const reader = new FileReader();
reader.onload = () => {
setImageSrc(reader.result as string);
};
reader.readAsDataURL(convertedFile);
} catch (error) {
console.log(error);
}
}
}
참고자료
browser-image-compression
Compress images in the browser. Latest version: 2.0.2, last published: 4 months ago. Start using browser-image-compression in your project by running `npm i browser-image-compression`. There are 120 other projects in the npm registry using browser-image-co
www.npmjs.com
'Web' 카테고리의 다른 글
[React] input에 입력할 때 글자 깜빡임 현상, 웹폰트 성능 최적화 (0) | 2023.06.18 |
---|---|
[React] npm i node-sass 에러 (0) | 2023.06.04 |
[React] 카카오 애드핏 에러 (useEffect, componentDidMount, useLayoutEffect) (0) | 2023.06.03 |
[HTML, JS] form을 이용한 데이터 POST 요청 시 Not Found 404 오류 (0) | 2023.05.29 |
[CSS] input password 안 보이는 현상 (0) | 2023.05.26 |