실습
이론만 다루면 아쉬우니, 서버는 Java 환경, 클라이언트는 JavaScript 환경에서, 위 흐름대로 직접 서비스를 구현한 코드 예시를 보여 드리며, 직접 실습하여 봅시다. Spring 환경 설정 관련해서는 [Framework/Spring] - [Spring] Spring Boot 환경설정 가이드 을 참고하시길 바랍니다. 코드 상에서 S3를 활용하기 위해선, 아래와 같은 작업들이 수반되어야 합니다.
- AWS 계정 생성
- IAM Role 또는 Access Key & Secret Key 생성
- AWS S3 버킷 생성
- S3 버킷 CORS 설정 (파일 업로드를 위해)
위와 관련된 부분은 본 게시글의 범위를 넘어가므로, 생략합니다.
- 환경설정
aws:
s3:
access: your-access-key # 수정 필요
secret: your-secret-key # 수정 필요
region: ap-northeast-2 # 서울 아닐 시, 수정 필요
놓치기 쉬운 부분이, 환경설정하는 부분입니다. 설정을 돕기 위해, 관련된 코드를 첨부합니다. 이와 같은 설정이 없으면, S3 접근 권한이 없습니다.
@Configuration
public class AwsFileConfig {
@Value("${aws.s3.access}")
private String accessKey;
@Value("${aws.s3.secret}")
private String secretKey;
@Value("${aws.s3.region}")
private String region;
@Bean
public AmazonS3 amazonS3() {
return AmazonS3ClientBuilder.standard()
.withRegion(region)
.withCredentials(new AWSStaticCredentialsProvider(amazonAWSCredentials()))
.build();
}
@Bean
public AWSCredentials amazonAWSCredentials() {
return new BasicAWSCredentials(accessKey, secretKey);
}
}
- 클라이언트가 파일 업로드 요청 (JavaScript)
아래는 클라이언트에서 사용자가 파일을 업로드하려고 할 때 서버로 요청을 보내는 예시 코드입니다. 참고로 업로드할 파일의 메타 정보나 이름을 포함할 수 있도록 body 값에 담아 보내줍니다.
async function requestPresignedUrl(fileName) {
// 서버에 presigned URL 요청
const response = await fetch('/generate-presigned-url', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ fileName: fileName })
});
if (response.ok) {
const { presignedUrl } = await response.json();
return presignedUrl;
} else {
throw new Error('Failed to fetch presigned URL');
}
}
async function uploadFileToS3(file) {
try {
// Presigned URL 요청
const presignedUrl = await requestPresignedUrl(file.name);
// S3로 파일 업로드
const response = await fetch(presignedUrl, {
method: 'PUT',
body: file
});
if (response.ok) {
console.log('File uploaded successfully.');
} else {
console.error('File upload failed.', response.statusText);
}
} catch (error) {
console.error('Error uploading file:', error);
}
}
클라이언트에서 서버로 파일 이름을 전송해 presigned URL을 요청하고, 받은 URL을 사용해 AWS S3에 파일을 업로드합니다.
- 서버에서 Presigned URL 생성 (Java)
서버는 클라이언트로부터 파일 업로드 요청을 받으면, AWS S3에 presigned URL을 생성하고 반환합니다. 여기서 중요한 부분은 presignedUrl의 접근 제한 시간을 설정하는 부분입니다. 아래 예시에선, LocalDateTime.now().plusMinutes(1L)로 설정 한 뒤, 타입 호환을 위해 자료형을 변경해 두었습니다. 또한 클라이언트에서 입력 받은 fileName을 반영하기 위해, ResponseHeaderOverrides 객체 안에 metadata 값으로 fileName을 받아줬습니다. key 값은 업로드 시, 파일 이름이 됩니다. 이는 중복이 되면 안되므로, UUID로 설정해줍니다.
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest;
import com.amazonaws.services.s3.model.ResponseHeaderOverrides;
@RestController
@RequiredArgsConstructor
public class FileUploadController {
private final AmazonS3 amazonS3;
@PostMapping("/generate-presigned-url")
public Map<String, String> generatePresignedUrl(@RequestBody Map<String, String> requestBody) {
String fileName = requestBody.get("fileName");
String uuidFileName = UUID.randomUUID().toString();
// 제한 시간을 1분으로 설정
LocalDateTime expirationTime = LocalDateTime.now().plusMinutes(1L);
Date expirationDate = Date.from(expirationTime.atZone(ZoneId.systemDefault()).toInstant());
// 메타데이터 저장
String encodedFilename = URLEncoder.encode(fileName, StandardCharsets.UTF_8);
ResponseHeaderOverrides responseHeaders = new ResponseHeaderOverrides().withCacheControl("No-cache");
responseHeaders.setContentDisposition("attachment; filename=\"" + encodedFilename + "\"");
GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(bucketName, uuidFileName)
.withMethod(HttpMethod.PUT)
.withExpiration(expirationDate)
.withResponseHeaders(responseHeaders);
// Presigned URL 생성
URL presignedUrl = amazonS3.generatePresignedUrl(generatePresignedUrlRequest);
// 클라이언트에 URL 반환
Map<String, String> response = new HashMap<>();
response.put("presignedUrl", presignedUrl.toString());
return response;
}
}
서버 환경은 Java Spring Boot 환경이며, presigned URL을 생성하는 예제입니다. 클라이언트로부터 파일 이름을 받아 해당 파일을 업로드할 수 있는 URL을 생성해 반환합니다.
- 클라이언트에 Presigned URL 반환
서버는 presigned URL을 JSON 형식으로 클라이언트에 반환합니다.
{
"presignedUrl": "https://your-bucket-name.s3.amazonaws.com/your-file.txt?X-Amz-Algorithm=..."
}
- 클라이언트가 URL을 통해 파일 업로드
클라이언트는 서버로부터 받은 presigned URL을 통해 AWS S3에 직접 파일을 업로드합니다. 이 단계는 JavaScript 코드에서 이미 처리되었습니다 (fetch API로 S3에 PUT 요청을 보내 파일을 업로드).
- 업로드 완료 후 확인 작업
파일이 성공적으로 업로드되었는지 확인하려면, S3에서 response.ok를 확인하고 그에 따라 후속 작업을 진행할 수 있습니다.
if (response.ok) {
console.log('File uploaded successfully.');
} else {
console.error('File upload failed.', response.statusText);
}
댓글