🎯문제
게시글을 작성할 때 사용자의 로그인이 필요하도록 코드를 작성함
그런데 기능 테스트 시 사용자 회원가입 및 로그인은 문제 없이 되나, 게시글 작성만 403 오류가 뜨며 진행이 되지 않음
원인

403 오류가 떴으므로 인증 관련 문제일 거라고 생각했으나, 로그를 보면 다음 단계를 거치는 걸 확인할 수 있음
- 게시글 작성 요청
- 인증 확인
- 415 오류 발생
- Spring이 /error로 POST 요청
SecureConfig에서 해당 url을 처리하는 부분이 없어 403 에러 발생
즉 사용자 인증에 실패하여 403 에러가 뜨는 것이 X
오류메시지를 자세히 들여다보면 아래와 같이 Content-Type 'application/octet-stream' is not supported 라는 문구가 있음
Could not resolve parameter [0] in public org.springframework.http.ResponseEntity<?> 프로젝트.controller.DiaryController.createDiary(프로젝트.dto.diary.DiaryCreateRequest,java.util.List<org.springframework.web.multipart.MultipartFile>,org.springframework.security.core.userdetails.UserDetails): Content-Type 'application/octet-stream' is not supported
Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content-Type 'application/octet-stream' is not supported]
해당 메서드의 첫 번째 파라미터의 콘텐츠 유형이 지원되지 않아 이를 해결할 수 없다는 내용
💡 application/octet-stream
HTTP에서 사용하는 MIME 타입(Content-Type) 중 하나
이 데이터가 어떤 형식인지 알 수 없을 때의 바이너리 데이터를 나타냄서버가 파일의 형식을 알 수 없을 때 그 파일을 바이너리 데이터로 보내고, 브라우저는 해당 파일을 화면에 표시하는 대신 다운로드를 진행함 --> zip,. exe, pdf 등을 다운로드 시키고 싶을 때 사용
문제가 발생한 코드는 아래와 같다
@PostMapping(path = "/post", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<?> createDiary(
@RequestPart("diary") DiaryCreateRequest request,
@RequestPart(value = "images", required = false) List<MultipartFile> images,
@AuthenticationPrincipal UserDetails userDetails
) {
// 코드 내용 ....
}
여기서 @RequestPart("diary")로 JSON을 받고 있는데, 클라이언트가 요청을 보낼 때 diary 파트의 Content-Type을 application/json으로 명시하지 않아 기본값인 application/octet-stream으로 전송되었음
이 타입을 Spring이 DiaryCreateRequest로 역직렬화 할 수 없기 때문에 415 Unsupported Media Type 에러가 발생한 것
해결
클라이언트에서 요청을 보낼 때, diary 파트에 Content-Type을 명시적으로 application/json으로 지정해야 함
다만 나는 지금 백엔드 개발 중이고, 당장 테스트 해봐야 하므로 서버 측에서 해결하는 방향으로 진행... (--> 추후 프론트엔드 개발 시 이 부분은 수정하기)
@RequestPart로 데이터를 받는 대신 String으로 먼저 받고 직접 파싱하기로 함
@PostMapping(path = "/post", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<?> createDiary(
@RequestPart("diary") String diaryJson, // String으로 받기
@RequestPart(value = "images", required = false) List<MultipartFile> images,
@AuthenticationPrincipal UserDetails userDetails
) {
// 입력 받은 String을 DTO로 직접 파싱함
DiaryCreateRequest request = objectMapper.readValue(diaryJson, DiaryCreateRequest.class);
// ...
}
추가로, 컨트롤러에서 따로 처리한 예외가 아니라면 오류 코드가 403으로만 보이는 현상도 피해야 함
전역 예외 핸들러 클래스를 작성하여 각각의 오류 코드가 정확히 보이도록 명시한다
@RestControllerAdvice
public class GlobalExceptionHandler {
// @Valid 검증 실패 시 (400)
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<?> handleValidationException(MethodArgumentNotValidException e) {
Map<String, String> errors = new LinkedHashMap<>();
e.getBindingResult().getFieldErrors()
.forEach(error -> errors.put(error.getField(), error.getDefaultMessage()));
return ResponseEntity.badRequest().body(errors);
}
// 지원하지 않는 Content-Type (415)
@ExceptionHandler(HttpMediaTypeNotSupportedException.class)
public ResponseEntity<?> handleMediaTypeNotSupported(HttpMediaTypeNotSupportedException e) {
return ResponseEntity.status(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
.body(Map.of("error", e.getMessage()));
}
}
결과


postman에서도, swagger에서도 게시글이 잘 작성되는 것을 확인할 수 있음

비밀번호 기준을 맞추지 못했을 때 에러코드가 400이 아닌 403이 떴었으나, 이젠 오류 메시지와 함께 400 에러코드가 뜨는 것을 확인할 수 있음
'트러블슈팅' 카테고리의 다른 글
| [트러블슈팅/SpringBoot] Nexacro Dataset 인식 안 됨 (0) | 2026.06.13 |
|---|---|
| [트러블슈팅/SpringBoot] Nexacro 연동 시 발생한 의존성 문제 (0) | 2026.06.12 |
| [트러블슈팅/SpringBoot] WebMvcTest로 Controller 테스트 시 JwtUtil 인식 안 됨 (1) | 2026.03.11 |
| [트러블슈팅/SpringBoot] Builder 필드 초기값 누락 (0) | 2026.01.22 |
| [트러블슈팅/GitHub] 원격저장소 - 로컬저장소 기록(history) 병합 (0) | 2026.01.17 |