WIL/웹 개발
Presigned URL을 사용한 파일 업로드 구현
아크리미츠
2024. 10. 15. 20:27
프리사인드 URL이란?
프리사인드 URL(Presigned URL)은 클라이언트가 서버를 거치지 않고, 직접 클라우드 저장소(예: AWS S3)에 파일을 업로드할 수 있도록 임시 권한을 제공하는 URL. 이 URL은 일정 시간 동안만 유효하고, 그 시간 안에만 지정된 파일을 업로드할 수 있음.
장점:
- 서버 부하 감소: 파일이 서버를 거치지 않고 클라이언트에서 클라우드로 바로 업로드되기 때문에 서버 자원이 절약됨.
- 보안 강화: URL은 제한된 시간 동안만 유효하고, 업로드할 수 있는 파일도 미리 지정되므로 안전함.
- 업로드 속도 향상: 클라이언트가 직접 파일을 올리기 때문에 업로드 속도가 더 빠름.
클라이언트 코드: 파일 업로드와 폼 제출
1. 파일 선택하고 폼 제출
const fileInput = document.getElementById('image');
const file = fileInput.files[0];
if (!file) {
document.getElementById('uploadForm').submit();
return;
}
- 사용자가 파일을 선택하지 않으면 그냥 폼을 제출하고 끝냄.
- 파일이 선택되었으면, 해당 파일을 처리하기 위해 프리사인드 URL을 요청하는 과정을 시작함.
2. 프리사인드 URL 요청
const fileName = encodeURIComponent(file.name);
const response = await fetch(`/presigned-url?filename=${fileName}`);
const presignedUrl = await response.text();
- 파일 이름을 URL에 맞게 인코딩해서 서버에 프리사인드 URL을 요청함.
- 서버에서 반환된 프리사인드 URL을 통해 파일을 업로드할 준비를 함.
3. 파일 업로드
const uploadResult = await fetch(presignedUrl, {
method: 'PUT',
headers: {
'Content-Type': file.type
},
body: file
});
- 프리사인드 URL을 사용해서 클라우드 저장소에 파일을 업로드함.
- 파일의 타입(MIME)을 헤더에 지정하고, PUT 메소드로 파일 데이터를 전송함.
4. 업로드 성공 시 폼 제출
if (uploadResult.ok) {
const imageUrl = presignedUrl.split("?")[0];
document.getElementById('imageUrl').value = imageUrl;
document.getElementById('uploadForm').submit();
}
- 파일 업로드에 성공하면, 업로드된 파일의 URL을 추출해 폼의 imageUrl 필드에 설정함.
- 이후 폼을 제출해서 서버로 다른 데이터와 함께 파일 URL도 전송함.
전체 코드
async function uploadAndSubmit(event) {
event.preventDefault();
const fileInput = document.getElementById('image');
const file = fileInput.files[0];
if (!file) {
document.getElementById('uploadForm').submit();
return;
}
const fileName = encodeURIComponent(file.name);
const response = await fetch(`/presigned-url?filename=${fileName}`);
const presignedUrl = await response.text();
const uploadResult = await fetch(presignedUrl, {
method: 'PUT',
headers: {
'Content-Type': file.type
},
body: file
});
if (uploadResult.ok) {
const imageUrl = presignedUrl.split("?")[0];
document.getElementById('imageUrl').value = imageUrl;
document.getElementById('uploadForm').submit();
} else {
console.error("파일 업로드 실패", uploadResult);
alert("파일 업로드에 실패했습니다.");
}
return false;
}
서버 코드: 프리사인드 URL 생성하기
클라이언트가 프리사인드 URL을 요청하면, 서버에서 그 URL을 생성해줘야 함. AWS S3의 프리사인드 URL을 생성하는 비즈니스 로직은 아래와 같음.
서버에서 프리사인드 URL 생성하기
// Controller
@GetMapping("/presigned-url")
@ResponseBody
String getURL(@RequestParam String filename) {
var result = s3Service.createPresignedUrl("test/" + filename);
return result;
}
// Service
public String createPresignedUrl(String path) {
var putObjectRequest = PutObjectRequest.builder()
.bucket(bucket)
.key(path)
.build();
var preSignRequest = PutObjectPresignRequest.builder()
.signatureDuration(Duration.ofMinutes(3))
.putObjectRequest(putObjectRequest)
.build();
return s3Presigner.presignPutObject(preSignRequest).url().toString();
}
PutObjectRequest
는 AWS S3에 업로드할 파일의 버킷과 경로(파일 이름)를 설정함.PutObjectPresignRequest
는 프리사인드 URL의 유효 시간을 설정하고, 3분 동안 URL이 유효하도록 설정함.s3Presigner
를 통해 프리사인드 URL을 생성하고, 해당 URL을 반환함.
서버에서는 클라이언트가 보낸 파일 경로를 받아서 이 URL을 생성해 클라이언트에 전달해줌. 클라이언트는 이 URL을 사용해 S3에 파일을 업로드하게 됨.
전체 플로우
- 파일 선택: 클라이언트에서 사용자가 파일을 선택함.
- 프리사인드 URL 요청: 클라이언트는 서버에 파일 이름을 보내서 프리사인드 URL을 요청함.
- 프리사인드 URL 생성: 서버는 AWS S3와 연동해 프리사인드 URL을 생성하고 클라이언트에 반환함.
- 파일 업로드: 클라이언트는 받은 프리사인드 URL을 사용해 파일을 S3에 업로드함.
- 폼 제출: 업로드가 완료되면, 클라이언트는 업로드된 파일의 URL을 폼에 포함시켜 제출함.