서버 배포하고 cors 에러도 다 고쳤겠다 싶어서 다 끝난줄...알았으나 갑자기 백엔드 측에서 헬프를 쳐서 급하게 코드를 다시 수정하게 되었다.
일반 이미지는 다 괜찮은데, 이미지가 큰 파일의 경우 이미지가 첨부가 안된다는것....
500에러가 뜨긴 했지만 느낌상 프론트 측에서 해결이 가능할 것 같았다.
아마 이미지 최적화 후(이미지 압축 or 이미지 리사이징) 서버에 보내면 수월하게 에러가 해결될 듯 싶었다.
이미지의 해상도를 유지하면서, 이미지의 크기를 줄여서 서버로 보내기 위해 이미지 압축을 이용해서 첨부된 이미지 압축 후 서버로 파일을 전송하기로 하였다.
라이브러리
browser-image-compression
npm i browser-image-compression --force
browser-image-compression 라이브러리를 사용했다.
해당 라이브러리는 아래와 같은 옵션이 있다.
const options = {
maxSizeMB: 1, // 최대 파일 크기를 1MB로 제한
maxWidthOrHeight: 1024, // 이미지의 최대 너비 또는 높이
useWebWorker: true, // 웹 워커 사용
};
web worker는 간단하게 말해 필요시 백그라운드에서도 스크립트를 사용하겠냐는 의미,
프론트엔드 인터페이스버 배포하고 cors 에러도 다 고쳤겠다 싶어서 다 끝난줄...알았으나 갑자기 백엔드 측에서 헬프를 쳐서 급하게 코드를 다시 수정하게 되었다.
일반 이미지는 다 괜찮은데, 이미지가 큰 파일의 경우 이미지가 첨부가 안된다는것....
500에러....
500에러가 뜨긴 했지만 느낌상 프론트 측에서 해결이 가능할 것 같았다.
아마 이미지 최적화 후(이미지 압축 or 이미지 리사이징) 서버에 보내면 수월하게 에러가 해결될 듯 싶었다.
이미지의 해상도를 유지하면서, 이미지의 크기를 줄여서 서버로 보내기 위해 이미지 압축을 이용해서 첨부된 이미지 압축 후 서버로 파일을 전송하기로 하였다.
라이브러리
browser-image-compression
npm i browser-image-compression --force
browser-image-compression 라이브러리를 사용했다.
해당 라이브러리는 아래와 같은 옵션이 있다.
const options = {
maxSizeMB: 1, // 최대 파일 크기를 1MB로 제한
maxWidthOrHeight: 1024, // 이미지의 최대 너비 또는 높이
useWebWorker: true, // 웹 워커 사용
};
web worker는 간단하게 말해 필요시 백그라운드에서도 스크립트를 사용하겠냐는 의미,
프론트엔드 인터페이스에는 딱히 방해되지 않으므로 true라고 디폴트 설정값 그대로 가져간 후에 이미지 압축 후 파일 전송을 적용해보자.
전체 코드
우선 전체 코드부터 작성
const handleImageChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
const files = e.target.files;
// 총 이미지 갯수 제한 확인 (새로 추가된 이미지와 기존 이미지 포함)
if (files && files.length + newImageFiles.length + prevImageUrls.length > 4) {
Swal.fire(
"Error",
"이미지는 최대 4개까지 업로드할 수 있습니다.",
"error"
);
return;
}
const fileArray = Array.from(files || []);
const options = {
maxSizeMB: 1, // 최대 파일 크기를 1MB로 제한
maxWidthOrHeight: 1024, // 이미지의 최대 너비 또는 높이
useWebWorker: true, // 웹 워커 사용
};
// 이미지 파일을 압축하고, 파일 이름을 정규화하여 새로운 File 객체로 반환
const compressedAndSanitizedFiles = await Promise.all(
fileArray.map(async (file) => {
try {
// 1. 이미지 압축
const compressedFile = await imageCompression(file, options);
// 2. 파일 이름 정규화
const sanitizedFileName = compressedFile.name
.normalize('NFKD') // 유니코드 정규화
.replace(/[\s]/g, '-') // 공백을 대시(-)로 변환
.replace(/[^a-zA-Z0-9.-]/g, ''); // 알파벳, 숫자, 점, 하이픈을 제외한 모든 문자 제거
// 3. 새 File 객체 생성 (압축된 파일에 정규화된 이름 적용)
return new File([compressedFile], sanitizedFileName, { type: compressedFile.type });
} catch (error) {
console.error('Error compressing the image:', error);
return file; // 압축 실패 시 원본 파일 사용
}
})
);
// 미리보기 URL 생성
const newUrls = compressedAndSanitizedFiles.map(file => URL.createObjectURL(file));
// 새로운 이미지 URL 및 파일을 상태로 업데이트
setNewImageUrls((prev) => [...prev, ...newUrls]);
setNewImageFiles((prev) => [...prev, ...compressedAndSanitizedFiles]);
};
fileArray는 첨부된 파일들이 담긴 배열이다. 해당 배열의 이미지 파일들을 하나하나 압축을 수행한다.
const options = {
maxSizeMB: 1, // 최대 파일 크기를 1MB로 제한
maxWidthOrHeight: 1024, // 이미지의 최대 너비 또는 높이
useWebWorker: true, // 웹 워커 사용
};
const compressedFile = await imageCompression(file, options);
options에서 세부사항 설정 후, 파일 배열의 파일들을 하나하나 가져와서 option을 적용하면 된다.
여기서 파일 이름의 정규화(sanitized)도 수행하기 위해 규칙을 더 선언해 주었다.
const sanitizedFileName = compressedFile.name
.normalize('NFKD') // 유니코드 정규화
.replace(/[\s]/g, '-') // 공백을 대시(-)로 변환
.replace(/[^a-zA-Z0-9.-]/g, ''); // 알파벳, 숫자, 점, 하이픈을 제외한 모든 문자 제거
return new File([compressedFile], sanitizedFileName, { type: compressedFile.type });
압축된 파일의 파일 이름을 정규화하기 위한 규칙을 세운 후, 이를 적용하기 위해 new File로 새 파일 객체를 만들고, 기존 압축된 파일의 파일 이름만 정규화된 파일 이름으로 바꾸어 주었다.
참고로 파일 이름도 한글/특수문자의 경우 s3에서 인식 못해서 에러가 발생할 수 있기 때문에(경험담....) 파일 이름도 sanitized한 후 파일을 첨부해서 전송해 보았다.
에러가 고쳐진 것을 확인할 수 있다.
'개발' 카테고리의 다른 글
[golang] go channel, go routine (1) | 2024.11.27 |
---|---|
[golang] A tour of Go exercise (0) | 2024.11.19 |
[golang] method, interface, pointer 개념 다시잡기 (0) | 2024.11.18 |
[Backend] golang backend 개발 -기초 (0) | 2024.11.12 |
github actions와 aws를 이용한 cicd pipeline 구축 (2) | 2024.09.05 |