본문 바로가기
Error

AWS S3 Upload 시 발생하는 No content length specified for stream data 해결 방법

by devLog by Ronnie's 2023. 7. 2.

AWS S3 버킷에 이미지를 업로드 도중 아래와 같은 로그가 발생하였다. 에러 해결 방법에 대해서 정리한다.

No content length specified for stream data. Stream contents will be buffered in memory and could result in out of memory errors

 

 

AWS S3 Upload 시 발생하는 No content length specified for stream data 해결 방법

 

 

AWS S3 error 해결 방법 

 

원인


S3에 이미지를 업로드를 구현하다보면 다음과 같은 로그를 발생한 사람들은 아마 이 글을 보고 있을 것이다.

 

로그는 아래와 같이 찍히며 로그 레벨에서도 알 수 있듯이 해당 로그가 발생하더라도 S3에 이미지가 업로드는 잘 된다.

[WARN] No content length specified for stream data. Stream contents will be buffered in memory and could result in out of memory errors.

 

하지만 어쨋든 경고를 주는 것이니 해결을 해야 할 것이다. 먼저 해당 로그의 원인은 업로드 하기 위해 만든 메다데이터 컨텐츠 길이 설정이 빠져서 그렇다.

 

아래 AWS 공식 문서에서는 다음과 같이 설명한다.

 

그리고 추가적으로 문서를 살펴보면 해결 방법도 친절히 알려준다.

 

 

 

해결 방법


아래는 길이 설정을 빼먹은 코드이며

public void s3PutOjectFromStreamNoncompliant(AmazonS3 s3Client, File inputFile) throws FileNotFoundException {
    String s3Bucket = "sample-bucket";
    FileInputStream inputStream = null;
    try {
        inputStream = new FileInputStream(inputFile);
        ObjectMetadata metadata = new ObjectMetadata();
        // Noncompliant: puts object from stream without specifying the content length of the stream.
        s3Client.putObject(s3Bucket, inputFile.getName(), inputStream, metadata);
    } finally {
        IOUtils.closeQuietly(inputStream, null);
    }
}

 

다음 코드가 길이 설정을 추가하여 로그가 발생하지 않는 코드이다.

public void s3PutOjectFromStreamCompliant(AmazonS3 s3Client, File inputFile) throws FileNotFoundException {
    String s3Bucket = "sample-bucket";
    FileInputStream inputStream = null;
    try {
        inputStream = new FileInputStream(inputFile);
        ObjectMetadata metadata = new ObjectMetadata();
        // Compliant: specifies the content length of the stream.
        metadata.setContentLength(inputFile.length());
        s3Client.putObject(s3Bucket, inputFile.getName(), inputStream, metadata);
    } finally {
        IOUtils.closeQuietly(inputStream, null);
    }
}

 

다음과 같이 ObjectMetadata에 대해 ContentLength에 대한 설정을 해줘야 한다.

metadata.setContentLength(inputFile.length());

 

근데 해당 예제는 File 클래스로 다룰때에 대한 설명이며, 만약 이미지를 Stream 형태로 핸들링하는 경우에는 어떻게 해야 될까?

 

InputStream ContentsLength 설정


해결방법은 아래와 같다.

val byteArrayOutputStream = ByteArrayOutputStream()
inputStream.copyTo(byteArrayOutputStream)

val objectMetadata = ObjectMetadata()
objectMetadata.contentLength = byteArrayOutputStream.size().toLong()

코드에서 알 수 있듯이 핸들링하고 있는 inputStream을 ByteArrayOutputStream으로 카피 이후 byteArrayOutputStream 에 대한 사이즈를 objectMetadata.contentLength 로 넘겨주면 된다.

 

 

참고 문서


https://docs.aws.amazon.com/codeguru/detector-library/java/s3-object-metadata-content-length-check/

 

Unchecked S3 object metadata content length | Amazon CodeGuru, Detector Library

Failure to specify a content length causes the contents of the input stream to buffer locally in memory in order to calculate its length. This can result in performance problems.

docs.aws.amazon.com

 

댓글