기존에 구현항 방식은 pre-signed url을 통해 프론트에서 S3 버킷에 직접 이미지를 업로드하는 방식이었다.
이미지를 서버를 거치지 않고 프론트에서 직접 S3 버킷으로 저장하는 방법은 네트워크 낭비를 줄일 수 있었다.
🔥 Problem
그러나 프론트에서 직접 S3에 이미지를 업로드하게 되면 다음과 같은 문제가 발생할 수 있다.
사용자가 업로드하는 이미지의 타입을 알 수 없다.
사용자가 업로드하는 이미지의 크기를 알 수 없다.
💡 Solution
위 문제를 방지하기 위해서는 클라이언트에서 S3에 직접 접근하는 것이 아닌 서버를 통해 이미지를 업로드하는 방법으로 수정해야 한다.
클라이언트에서 서버로 이미지 업로드
클라이언트에서 전송한 이미지 형식과 크기를 확인한 후 규격에 맞으면 이미지를 S3에 저장한다.
만약 클라이언트가 전송한 이미지가 규격에 맞지 않으면 예외처리를 수행한다.
1. 저장할 파일 이름의 형식
Amazon S3는 파일 이름의 형식에 제한을 두지 않는다.
하지만 URL 경로나 파일 이름에 유니코드 문자나 특수 문자가 포함될 경우 문제가 발생할 수 있다.
파일 이름을 URL 경로로 사용할 때 인코딩 문제가 발생할 수 있다.
따라서 Java.util에서 제공하는 URLEncoder 를 이용하여 클라이언트로부터 전달 받은 fileName을 encode 한다.
2. 파일 이름 중복
S3 bucket에 파일 이름이 jari-bean.png에 해당하는 이미지 파일이 존재하고,
파일 이름이 같은 jari-bean.png 인 파일을 S3 bucket에 저장할 경우 기존에 존재하던 이미지를 덮어쓴다.
다시 말하면 기존의 jari-bean.png 이미지는 사라지게 된다.
업로드 파일 이름 중복이 발생하여 기존 파일이 삭제되는 것을 방지하기 위해 encode된 fileName 앞에 임의적으로 생성한 uuid를 붙여준다.
업로드가 가능한 파일의 최대 사이즈(10MB)를 초과할 경우 발생할 Exception을 처리하는 Handler
@ExceptionHandler(SizeLimitExceededException.class)
public ResponseEntity sizeLimitExceededException(SizeLimitExceededException e) {
log.error(e.getMessage());
return new ResponseEntity<>(new ResponseDto<>(-1, e.getMessage(), "업로드가 가능한 파일의 용량은 최대 10MB입니다."), HttpStatus.INTERNAL_SERVER_ERROR);
}
URLEncoeer의 encode() 메서드에서 문제가 발생할 경우 Exception을 처리하는 Handler
@ExceptionHandler(UnsupportedEncodingException.class)
public ResponseEntity unsupportedEncodingException(UnsupportedEncodingException e) {
log.error(e.getMessage());
return new ResponseEntity<>(new ResponseDto<>(-1, e.getMessage(), "filename의 URL encode에 문제가 발생하였습니다. "), HttpStatus.INTERNAL_SERVER_ERROR);
}
✏️ Description
기존에 구현항 방식은 pre-signed url을 통해 프론트에서 S3 버킷에 직접 이미지를 업로드하는 방식이었다. 이미지를 서버를 거치지 않고 프론트에서 직접 S3 버킷으로 저장하는 방법은 네트워크 낭비를 줄일 수 있었다.
🔥 Problem
그러나 프론트에서 직접 S3에 이미지를 업로드하게 되면 다음과 같은 문제가 발생할 수 있다.
💡 Solution
위 문제를 방지하기 위해서는 클라이언트에서 S3에 직접 접근하는 것이 아닌 서버를 통해 이미지를 업로드하는 방법으로 수정해야 한다.
1. 저장할 파일 이름의 형식
Amazon S3는 파일 이름의 형식에 제한을 두지 않는다. 하지만 URL 경로나 파일 이름에 유니코드 문자나 특수 문자가 포함될 경우 문제가 발생할 수 있다. 파일 이름을 URL 경로로 사용할 때 인코딩 문제가 발생할 수 있다.
따라서 Java.util에서 제공하는
URLEncoder
를 이용하여 클라이언트로부터 전달 받은fileName
을 encode 한다.2. 파일 이름 중복
S3 bucket에 파일 이름이
jari-bean.png
에 해당하는 이미지 파일이 존재하고, 파일 이름이 같은jari-bean.png
인 파일을 S3 bucket에 저장할 경우 기존에 존재하던 이미지를 덮어쓴다. 다시 말하면 기존의jari-bean.png
이미지는 사라지게 된다.업로드 파일 이름 중복이 발생하여 기존 파일이 삭제되는 것을 방지하기 위해 encode된
fileName
앞에 임의적으로 생성한uuid
를 붙여준다.🛠 Feature
S3Controller.java
클라이언트에게 직접 이미지를 받을 수 있도록 로직 변경
S3Service.java
S3 bucket에 저장할 파일 이름을 생성하는 메서드
UUID
를 붙여준다.URLEncoder
로 파일이름을encode()
한다.클라이언트가 업로드한 파일의 타입을 체크하는 메서드
클라이언트가 업로드한 파일을 S3 bucket에 저장하는 메서드
CustomExceptionHandler.java
업로드가 가능한 파일의 최대 사이즈(
10MB
)를 초과할 경우 발생할 Exception을 처리하는 HandlerURLEncoeer
의encode()
메서드에서 문제가 발생할 경우 Exception을 처리하는 Handlerapplication-s3.yml
파일 업로드 사이즈를 10MB로 제한하기 위한 설정