Project/Afternote

[CDN] S3 presigned URL에서 CDN 도메인 전환하기

gyuun365 2026. 4. 12. 02:05

기존 S3으로만 진행하던 로직들에 CDN 을 넣어서 조금 더 보완했습니다.

CDN을 넣은 이유

  • S3 Bucket을 CDN으로만 데이터를 접근하게 함으로써 보안 효과를 받게하고 확장성까지 커진다는
  • 만약 미래에 프로젝트가 해외까지 진출하게 되도 S3 관련 로직들은 CDN으로 인해 전세계에서 접속 가능해  성능 향상에 도움이 됨

AS-IS / TO-BE

크게 알아야 하는 것은 업로드 로직은 그대로 기존 방식을 이용하고 조회 로직에서 조금 바뀌었다.

[업로드: S3 직접 업로드의 효율성 유지]

보안이 걱정될 수 있지만, Presigned URL은 서버가 발행한 일회용 티켓임. CloudFront를 거치지 않고 S3로 직접 업로드하게 하여 서버의 네트워크 부하를 줄이고 비용을 절감하는 정석적인 방식을 채택했다.

[조회: CDN을 통한 보안과 가속]

조회는 CloudFront를 거치도록 설계했다. 이를 통해 S3 버킷을 외부에 공개하지 않고도(OAC) 전 세계 사용자에게 빠른 속도로 콘텐츠를 전달할 수 있는 보안성과 성능을 모두 잡았다.

CDN domain 환경변수 추가

    public-base-url: ${AWS_PUBLIC_BASE_URL:}

 

공개 URL 생성 로직 

public String resolvePublicUrl(String rawUrlOrKey) {
    if (!StringUtils.hasText(rawUrlOrKey)) {
        return null;
    }

    String key = extractStorageKey(rawUrlOrKey);
    if (!StringUtils.hasText(key)) {
        return rawUrlOrKey;
    }

    return buildPublicPrefix() + key;
}

 

그 외 추가된 함수

sanitizeKey()

경로 앞의 불필요한 슬래시(/)를 제거해 // 같은 경로 오류를 원천 차단한다.

private String sanitizeKey(String key) {
    // 1. 빈 값 체크
    if (!StringUtils.hasText(key)) {
        return null;
    }

    // 2. 양끝 공백 제거 + 앞부분 슬래시(/) 제거
    String sanitized = key.trim().replaceFirst("^/+", "");
    
    // 3. 결과값이 비어버렸다면 null 반환
    return sanitized.isBlank() ? null : sanitized;
}

만약 사용자가 실수로 키 값 앞뒤로 스페이스를 넣거나 중복 슬래시 같은 경우를 방지하기 위해 데이터의 불순물을 제거하는 함수를 생성

 

 

 

 

바뀐 흐름

  1. 클라이언트가 서버에 presigned URL을 요청한다.
  2. 서버는 presignedUrl, fileKey, fileUrl을 내려준다.
  3. 클라이언트는 presignedUrl로 S3에 직접 업로드한다.
  4. 클라이언트는 DB 저장용으로 fileKey를 서버에 전달한다.
  5. 서버는 DB에는 key만 저장한다.
  6. 조회할 때는 서버가 CDN domain + key 형태로 최종 URL을 만들어 내려준다.