Presign URL
S3 버킷에 이미지를 저장할 때 이전 글에서 했던 방식대로 백엔드 서버에서 SDK로 저장할 수 있었다.
하지만 이번 글에서는 조금 다른 방식으로 프론트엔드 서버에서 이미지를 저장해보려 한다.
프론트 엔드 서버에서도 AWS SDK를 이용하면 이미지를 저장할 수 있다.
하지만 프론트 쪽은 브라우저의 개발자 도구로 민감한 정보를 보기 편하기 때문에 꺼려진다.
그래서 이번에 써볼건 Presign URL 방식인데, 간단히 설명하자면 S3 버킷에 이미지를 저장할 수 있는 권한을 가진 URL이다.
이 URL로 몇번이고 S3 버킷에 요청을 할 수 있기 때문에 유효시간을 지정하여 발급한다.
프리사인 URL의 흐름은 아래와 같다.
- 프론트에서 백엔드로 이미지 파일명을 보내서 프리사인 URL을 요청한다.
- 백엔드는 요청 받은 이미지 파일명으로 S3 버킷에 저장할 수 있는 프리사인 URL을 발급한다.
- 프론트에서 프리사인 URL에 PUT 요청으로 이미지를 저장한다.
사용 기술
- Spring Boot 3.2.4 / gradle-kotlin
- Java 17
- Aws SDK
1. AwsConfig 설정
AwsConfig
S3 프리사이너를 빈 등록 한다.
Aws 관련 yml 설정은 이 글의 내용과 동일하다.
@RequiredArgsConstructor
@ConfigurationProperties(prefix = "aws")
public class AwsConfig {
private final String accessKey;
private final String secretKey;
private final String s3AccessPoint;
public String getS3AccessPoint() {
return s3AccessPoint;
}
@Bean
public S3Presigner s3Presigner() {
return S3Presigner.builder()
.credentialsProvider(getAwsBasicCredentials())
.region(Region.AP_NORTHEAST_2)
.build();
}
private StaticCredentialsProvider getAwsBasicCredentials() {
return StaticCredentialsProvider.create(
AwsBasicCredentials.create(accessKey, secretKey)
);
}
}
2. ImageService 구현
ImageService
사실 프리사인 URL이라고 별게 있는건 아니고 컨트롤러에서 받아온 filename 하나만 있으면 된다.
이 파일 이름을 UUID로 변환하든, 파일 이름 그대로 저장하든 편한대로 로직을 구성하면 된다.
나머지는 백엔드 환경 변수에 설정한 Aws 설정 값들로 프리사인 URL을 만든다.
아래처럼 프리사인 리퀘스트를 만들고 프리사인을 해서 프리사인 URL 을 만들고 응답 값으로 주면 된다.
여기서는 프리사인 URL을 PUT 메서드로 요청하게끔 설정하였다.
유효기간은 5분으로 주었다.
@Service
@RequiredArgsConstructor
public class ImageService {
private final AwsConfig awsConfig;
private final S3Presigner s3Presigner;
public String getPresignedUrl(String filename) {
if (filename == null || filename.isBlank()) {
throw new IllegalArgumentException("파일명을 확인해주세요.");
}
return generatePresignedUrl(filename);
}
private String generatePresignedUrl(String filename) {
PutObjectRequest putObjectRequest = PutObjectRequest.builder()
.bucket(awsConfig.getS3AccessPoint())
.key(filename)
.build();
PutObjectPresignRequest presignRequest = PutObjectPresignRequest.builder()
.signatureDuration(Duration.ofMinutes(5))
.putObjectRequest(putObjectRequest)
.build();
try (S3Presigner presigner = s3Presigner) {
return presigner.presignPutObject(presignRequest)
.url()
.toString();
}
}
}
3. 결과 확인
3-1. 프리사인 URL 발급 요청
프리사인 URL을 생성하는 컨트롤러를 만들었다.
아래처럼 파일 이름을 요청 값으로 보내고 프리사인 URL을 발급 받았다.
요청 값에 입력한 파일명이 string 이므로 S3에 string이라는 이름으로 저장될 것이다.
3-2. 프리사인 URL로 PUT 요청
아래 사진 처럼 form-data 형식으로 PUT 메서드로 저장하고자 하는 이미지를 넣어 요청한다.
여기서 요청하는 이미지 파일의 이름이나 key 값은 의미가 없고 프리사인 URL 발급 시 지정한 이름으로 S3 버킷에 저장된다.
아래 사진 처럼 200번 응답이 오면 성공한것이다.
실패할 경우 에러 페이지가 출력된다.
3-3. S3 버킷 확인
아래처럼 string 이라는 이름으로 파일이 저장됨을 알 수 있다.
4. PostMan이 아닌 프론트에서 요청할 때
CORS는 웹 브라우저의 보안 기능이다.
웹 브라우저는 스크립트가 현재 페이지와 다른 도메인으로 요청을 보낼 때 이를 제한하기 위해 CORS 정책을 적용한다.
포스트맨과 같은 API 테스트 도구는 브라우저가 아니므로, CORS 정책을 적용하지 않는다.
따라서 위처럼 해도 CORS 에러가 발생하지 않는다.
하지만 프론트엔드와 연동하면 브라우저에서 요청하기 때문에 CORS 에러가 뜬다.
CORS 에러를 막기 위해서는 S3 버킷에서 권한 처리를 해줘야한다.
아래처럼 S3 버킷에 들어가서 권한 탭에서 CORS 설정을 해주도록 한다.
본인은 PUT 요청으로 프리사인 URL을 만들었으므로 아래처럼 설정해주었다.
'API 만들어 보기 > 이미지 저장' 카테고리의 다른 글
이미지 저장 2: Aws SDK로 S3에 이미지 저장 (0) | 2024.04.13 |
---|---|
이미지 저장 1: S3 이미지 저장소 생성 (0) | 2024.04.12 |