
0. Presigned URL이란?
PreSigned Url은 말 그대로 미리 서명한 Url이라는 뜻이다. S3의 소유자가 미리 특정 권한(파일 업로드, 파일 다운로드 등)에 대해 서명을 해준 뒤 사용자에게 해당 Url을 제공해준다. 사용자는 서명된 권한을 사용할 수 있다. 소유자가 여러 정보에 대해 미리 서명을 해두고, 사용자가 추후에 전달받아 사용한다는 점에서 수표와 비슷하다.
PreSigned Url을 사용하게 된다면, 클라이언트가 서버에 거치지 않고 파일을 저장소에 직접 업로드할 수 있어, 서버의 자원을 절약할 수 있다.
사용자는 이미지를 S3에 올리기 위해 S3의 Presigned URL이 필요하다.
1. 클라이언트가 서버에 Presigend URL 요청
let presigned_url = await fetch("/item/presigned-url?filename=" + name);
2. 서버는 S3에 Presigned URL 요청
public String createPresignedUrl(String path) {
var putObjectRequest = PutObjectRequest.builder()
.bucket(bucket) // 올릴 버킷명
.key(path) // 경로
.build();
var preSignRequest = PutObjectPresignRequest.builder()
.signatureDuration(Duration.ofMinutes(3)) //url 유효기간
.putObjectRequest(putObjectRequest)
.build();
return s3Presigner.presignPutObject(preSignRequest).url().toString(); //presigned url Return
}
3. S3는 서버에 Presigned URL 제공
S3에서 주는데 http:~&a:b 이런식으로 이미지경로 + 쿼리스트링 형태로 제공해준다.
4. 서버는 클라이언트에 Presigned URL 제공
let presigned_url = await fetch("/item/presigned-url?filename=" + name);
1번에한 Get요청의 return 값(presigned_url)으로 받는다.
5. 클라이언트는 S3 Presigned URL에 Put 요청 보내서이미지 저장
let res = await fetch(presigned_url, {
method: "PUT",
body: file
});
이렇게 Put요청을 presigend_url로 보내면 이미지가 저장된다.
6. DB에는 S3에 저장된 이미지 경로 저장
사용자 클라이언트에 image_url에 S3이미지 경로(presigned_url에서 쿼리스트링을 뺀)로 보내주고 item게시 포스트 요청시 해당 url을 서버에 보내 이미지 URL을 DB에 저장되게 하였다.
const url = presigned_url.split("?")[0]; // 해당 url에서 쿼리스트링 뺀거
document.getElementById("imgUrl").value = url;
아래는 add api
@PostMapping("/add")
String add(String title, int price, String imgUrl ,Model model, Authentication auth ) {
String usrid=auth.getName();
boolean result = itemService.SavaItem(title, price, model,usrid, imgUrl);
System.out.println(imgUrl);
if (!result) {
return "item/write"; // 실패 시 다시 입력페이지로
}
return "redirect:/item/list"; // 성공 시 리스트로
}
가. 서버 부담 감소
이미지를 직접 서버에 보내지 않아도 된다. 클라이언트에서 Put 요청을 통해 바로 S3에 올리는 형태이기 때문이다.
대신 DB는 S3에 저장된 이미지의 URL만 가지고 있음.
가. fetch(/url?쿼리파라미터) Get 요청
위 함수를 사용하면 서버에 Get 요청을 보낼 수 있다.
url 을 가진 서버 api에 get요청을 보내고 파라미터로 ? 뒤에 오는 쿼리파라미터를 보낸다.
나. @Value("${spring.cloud.aws.s3.bucket}")
application.properties에 있는 버킷명 가져와서 아래 버킷 변수에 넣어달라는 Spring 어노테이션
@Value("${spring.cloud.aws.s3.bucket}") //application.properties에 있는 버킷명 가져와서 아래 버킷 변수에 넣어달라는 어노테이션
private String bucket;
private final S3Presigner
서버의 부담이 상당히 감소하는 것을 느낄 수 있었다.
| 항목 | Env Info |
|---|---|
| 🖥️ 서버 | Tomcat |
| 🍭 프레임워크 | Spring Boot |
| 📀 데이터베이스 | MySQL with Azure |
| 📝 JPA | Hibernate |
| 🙈 외부 라이브러리 | lombok, thymeleaf, AJAX |
| 📏 디자인 패턴 | MVC |