문제 상황
분명 이렇게 accept로 제한해뒀는데... 다른 파일도 잘 업로드 되는 문제가 발생했다.
<input
type="file"
hidden
accept="image/* .jpg, .png, .jpeg"
ref={fileInput}
onChange={onChange}
/>
해결 과정
accept 속성은 브라우저에서 사용자가 파일 선택 대화상자를 통해 선택할 수 있는 파일 유형을 제한한다.
따라서 처음에 파일 업로드 버튼을 눌렀을 때 나오는 파일창에서는 형식이 '사용자 지정파일(accept로 설정해둔 형식들)'로 제한되어있다. 하지만 이렇게 사용자가 형식을 '모든 파일'로 바꿔버리면 accept 설정이 소용없어진다.
TCPschool에서도 accept 속성을 유효성 검사를 도구로 사용해서는 안 되며, 업로드된 파일은 서버에서 검증되어야 한다고 써놨다.
결과
따라서 이렇게 클라이언트쪽에서 확장자를 직접 검사하는 함수를 만들거나, 서버에서 특정 파일만 받을 수 있게 처리해야한다.
이미 서버에서도 형식을 제한해놨지만 맞지 않는 형식인데도 API를 호출하는건 자원 낭비라고 생각해서 클라이언트단에서도 유효성 검사를 하는 코드를 작성했다.
const MAX_IMAGE_SIZE_BYTES = 1024 * 1024 * 10
const ALLOWED_EXTENSIONS = ['jpg', 'jpeg', 'png']
const isValidExtension = (filename: string) => {
const extension = filename.split('.').pop()?.toLowerCase()
return extension ? ALLOWED_EXTENSIONS.includes(extension) : false
}
const handleImgChange = async (file: File) => {
if (!isValidExtension(file.name)) {
alert(
'허용되지 않은 파일 형식입니다. jpg, jpeg, png 파일만 업로드해주세요.',
)
return
}
if (file.size > MAX_IMAGE_SIZE_BYTES) {
alert('파일 크기는 10MB 이하여야합니다.')
return
}
if (file instanceof File) {
try {
const response = await imageChange(file)
if (response.status === 200) {
const newImg = response.data.profileImgUrl
setUserDetails((prevState) => {
if (prevState) {
return {
...prevState,
profileImg: newImg,
}
}
return prevState
})
}
} catch (error) {
throw error
}
}
}
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.files) {
const file = e.target.files[0]
if (file) {
handleImgChange(file)
}
}
}
'나도 공부한다 > React' 카테고리의 다른 글
리액트 라우터를 알아보자 (리액트 인터뷰 가이드 4장 보충) (1) | 2024.10.29 |
---|---|
프레그먼트를 알아보자 (0) | 2024.10.23 |
React "too many re-render" 문제 해결 (0) | 2024.02.01 |
React의 Context API 알아보기 (0) | 2024.01.12 |
useReducer hook을 이용하여 리액트 상태관리 해보기 (0) | 2024.01.08 |