2024년 1월 10일
조회 : 194|1분 읽기

Cloudflare R2 - 사용

Cloudflare R2의 최신 기능들 중 사용할 수 없는것이 있을 수 있지만 ASW S3 SDK로 빠르고 간단하게 사용할 수 있습니다.

업로드

이때 메타 데이터를 사용합니다.
키값은 소문자로 변경됩니다.
java
1	// 이미지 path를 만들 유니크한 객체 2개, 이미지를 받음
2    public void uploadPlantImage(User user, Plant plant, ByteBuffer imageBuffer) {
3	    // 이미지를 분별할 해시 값 생성
4        String imageHash = cloudFlareR2Utils.calculateImageHash(imageBuffer);
5
6		// 이미지의 위치 지정
7        String imageType = "thumbnail";
8        String filePath = user.getEmail() + "/" + plant.getId()
9                + "/" + imageType + "/image.jpg";
10
11        String fileName = storagePointUri + filePath;
12        plant.setImgUrl(fileName);
13        logger.info("img URL :: {}", plant.getImgUrl());
14
15		// R2에 Object 전송
16        putObjectToR2(imageBuffer, imageHash, filePath);
17    }
18    
19    
20    
21        private void putObjectToR2(ByteBuffer imageBuffer, String imageHash, String filePath) {
22        PutObjectRequest putObjectRequest = PutObjectRequest.builder()
23                .bucket(bucketName)
24                .contentType("image/jpeg") // MIME 타입 설정
25                .metadata(Map.of("Content-Disposition", "inline", "image-hash", imageHash))
26                .key(filePath).acl(ObjectCannedACL.PUBLIC_READ)
27                .build();
28
29        s3Client.putObject(putObjectRequest, RequestBody.fromByteBuffer(imageBuffer));
30    }

수정

  1. 이미지에 메타태그를 설정하고 같은 이미지라면 업로드하지 않도록 만듭니다.
  2. 만약 이미지를 수정해야한다면 CDN에 있는 캐싱을 삭제하도록합니다.
java
1
2    public void editPlantImage(User user, Plant plant, ByteBuffer imageBuffer) {
3        String imageType = "thumbnail";
4        String filePath = user.getEmail() + "/" + plant.getId() + "/" + imageType + "/image.jpg";
5        String fileName = storagePointUri + filePath;
6
7		// 해시값 생성
8        String imageHash = cloudFlareR2Utils.calculateImageHash(imageBuffer);
9
10        String existingImageHash = retrieveImageHashFromR2(filePath);
11
12        // 이미지 해시 비교
13        if (!imageHash.equals(existingImageHash)) {
14            logger.info("Image hash Changed now : {}, exist : {}", imageHash, existingImageHash);
15
16			// 이미지 업로드
17            uploadPlantImage(user, plant, imageBuffer);
18            // 이미지 다르면 캐시 삭제
19            cloudFlarePurgeCache.purgeCache(fileName);
20
21        }
22    }
23    
24    // 존재했던 이미지의 해시값 찾기
25      public String retrieveImageHashFromR2(String filePath) {
26        try {
27            HeadObjectResponse response = s3Client.headObject(HeadObjectRequest.builder()
28                    .bucket(bucketName)
29                    .key(filePath)
30                    .build());
31
32            return response.metadata().get("image-hash");
33        } catch (S3Exception e) {
34            throw new RuntimeException("Failed to retrieve image hash from R2", e);
35        }
36    }

삭제

키값을 받고 안에 있는 객체들을 모두 삭제합니다.
java
1
2 public void deletePlant(Long plantId, String userEmail) {
3
4        try {
5            String filePath = userEmail + "/" + plantId;
6
7			// plantId의 하위 키값들을 모두 가져올 준비
8            ListObjectsRequest listObjects = ListObjectsRequest.builder()
9                    .bucket(bucketName)
10                    .prefix(filePath) // userEmail/PlantId/
11                    .build();
12
13            ListObjectsResponse listObjectsResponse = s3Client.listObjects(listObjects);
14            
15            // 하위 키를 사용해 모두 삭제
16            for (S3Object object : listObjectsResponse.contents()) {
17                DeleteObjectRequest deleteRequest = DeleteObjectRequest.builder()
18                        .bucket(bucketName)
19                        .key(object.key())
20                        .build();
21                s3Client.deleteObject(deleteRequest);
22            }
23
24
25        } catch (S3Exception e) {
26            // 로그 기록, 예외 처리 로직
27            throw new RuntimeException("파일 삭제 중 오류가 발생했습니다.", e);
28        }
29    }

결론

Cloudflare R2의 최대 장점은 아웃바운드 Get의 비용과 저장비용이 저렴한 것입니다.
따라서 최대한 장점을 살리기 위해선 Put을 줄여야 하기 때문에 메타태그를 사용해 수정을 줄인다면 더 저렴하게 이용할 수 있습니다.