Spring Boot에서 게시글 생성 시 파일(이미지, 동영상)을 첨부해 AWS S3에 업로드하도록 구현했다.
하지만 Postman으로 테스트하던 중 다음과 같은 에러가 발생했다.
2025-04-12T01:19:02.529+09:00 WARN 47568 --- [gigsync] [nio-8080-exec-7]
.w.s.m.s.DefaultHandlerExceptionResolver :
Resolved [org.springframework.web.HttpMediaTypeNotSupportedException:
Content-Type 'application/octet-stream' is not supported]
파일 업로드 자체가 실패했고, 이후 S3 버킷을 확인해도 업로드된 파일은 application/octet-stream 타입으로 설정되어 있었으며 브라우저에서 바로 열 수 없고 다운로드만 되는 문제가 발생했다.
이 문제는 크게 두 가지 원인으로 나눌 수 있었다.
MultipartFile>)을 동시에 받는 구조였는데, Postman에서 JSON을 잘못 설정하거나 Content-Type을 생략하면 Spring이 인식하지 못해 위 에러가 발생함Postman에서 요청을 multipart/form-data로 정확히 설정하고 @RequestPart에는 application/json 형태의 문자열을 전달하였다. 업로드 파일의 Content-Type을 MultipartFile.getContentType()으로 명시하고, 이미지 업로드 시 허용된 확장자만 가능하도록 설정했다.

@Service
@RequiredArgsConstructor
public class FileService {
private static final List<String> ALLOWED_IMAGE_EXTENSIONS = List.of("jpg", "jpeg", "png", "gif");
private final S3Client s3Client;
@Value("${cloud.aws.s3.bucketName}")
private String bucketName;
public List<BoardFile> uploadFiles(List<MultipartFile> files, Board board) {
List<BoardFile> result = new ArrayList<>();
for (MultipartFile file : files) {
String originalFilename = file.getOriginalFilename();
String extension = getExtension(originalFilename);
if (isImage(file) && !ALLOWED_IMAGE_EXTENSIONS.contains(extension.toLowerCase())) {
throw new IllegalArgumentException("지원하지 않는 이미지 형식입니다: " + extension);
}
String fileName = UUID.randomUUID() + "_" + originalFilename;
String url = uploadToS3(file, fileName);
result.add(BoardFile.builder()
.fileName(fileName)
.fileUrl(url)
.board(board)
.build()
);
}
return result;
}
private String uploadToS3(MultipartFile file, String fileName) {
try {
PutObjectRequest putObjectRequest = PutObjectRequest.builder()
.bucket(bucketName)
.key(fileName)
.acl("public-read")
.contentType(file.getContentType())
.build();
s3Client.putObject(putObjectRequest, RequestBody.fromInputStream(file.getInputStream(), file.getSize()));
return "https://" + bucketName + ".s3.amazonaws.com/" + fileName;
} catch (IOException e) {
throw new RuntimeException("파일 업로드 중 오류 발생", e);
}
}
private boolean isImage(MultipartFile file) {
String contentType = file.getContentType();
return contentType != null && contentType.startsWith("image");
}
private String getExtension(String filename) {
if (filename == null || !filename.contains(".")) {
throw new IllegalArgumentException("파일 이름에 확장자가 없습니다.");
}
return filename.substring(filename.lastIndexOf('.') + 1);
}
}


확장자 검증으로 잘못된 파일 업로드를 방지하고 S3 URL을 게시판 조회 시 바로 사용할 수 있게 되었다.
이번 이슈는 흔하지만 초반에 놓치기 쉬운 Content-Type과 multipart/form-data 처리에 대한 실수였다. Spring Boot와 S3 연동 시에는 아래 항목들을 꼭 챙기자 !