front에서 직접 이미지를 올리더라도, S3의 bucket URL 및 키를 모두 front에서 관리하는 것은 보안상 위험하므로
Backend에서 pre-signed URL을 프론트로 주면, front에서 그 URL을 이용해서 올리는 방식이 권장된다.
pre-signed URL은 설정한 시간(예: 1시간) 동안 유효하다.
java 백엔드에서 pre-signed URL을 생성하고, front에서 react를 이용해서 파일을 올리는 예제는 다음과 같다.
백엔드: AWS-SDK이용.
import com.amazonaws.HttpMethod;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.net.URL;
import java.util.Date;
@Service
public class S3Service {
private final AmazonS3 s3Client;
private final String bucketName;
public S3Service(
@Value("${aws.accessKeyId}") String accessKeyId,
@Value("${aws.secretKey}") String secretKey,
@Value("${aws.region}") String region,
@Value("${aws.s3.bucketName}") String bucketName) {
this.bucketName = bucketName;
this.s3Client = AmazonS3ClientBuilder
.standard()
.withRegion(region)
.withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(accessKeyId, secretKey)))
.build();
}
public URL generatePresignedUrl(String objectKey, HttpMethod httpMethod, long expirationInSeconds) {
Date expirationDate = new Date(System.currentTimeMillis() + (expirationInSeconds * 1000));
GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(bucketName, objectKey)
.withMethod(httpMethod)
.withExpiration(expirationDate);
return s3Client.generatePresignedUrl(generatePresignedUrlRequest);
}
}
FrontEnd:
import React, { useState } from 'react';
import axios from 'axios';
function FileUpload() {
const [selectedFile, setSelectedFile] = useState(null);
const handleFileChange = (event) => {
setSelectedFile(event.target.files[0]);
};
const handleUpload = async () => {
if (!selectedFile) {
console.log('Please select a file.');
return;
}
try {
// Replace with your backend API endpoint that generates the Pre-signed URL
const response = await axios.get('http://your-backend-api/generatePresignedUrl', {
params: {
objectKey: 'example.jpg', // 업로드할 객체의 키
httpMethod: 'PUT', // 업로드할 때 사용할 HTTP 메서드 (PUT 또는 POST)
expirationInSeconds: 3600, // URL의 유효 기간 (1시간)
},
});
const { url } = response.data;
// Use the obtained Pre-signed URL to upload the file directly to S3
await axios.put(url, selectedFile, {
headers: {
'Content-Type': selectedFile.type,
},
});
console.log('File uploaded successfully.');
} catch (error) {
console.error('Error uploading file:', error);
}
};
return (
<div>
<input type="file" onChange={handleFileChange} />
<button onClick={handleUpload}>Upload</button>
</div>
);
}
export default FileUpload;