문제 발생 배경
Mutlipart form 형식 필요와 문제
- image를 보내야하는경우 Multipart 요청을 보내야함
- 근데 이제 request json과 image를 동시에 받아야하는경우 문제가 발생
- mutlipart에서 applicaton/json으로 Content-Type지정이 필요
Swagger UI의 한계
- Postman에서는 Content Type지정이 가능
- Swagger UI에서는 각 파트별로 Content-Type을 명시적으로 설정 불가능
- 기본설정이 application/octet-stream 이다
오류 발생
- 서버에서는 application/octet-stream을 처리할 수 없다는 HttpMediaTypeNotSupportedException(415 UNSUPPORTED_MEDIA_TYPE) 오류가 발생
해결 시도 및 방법
기본적으로 2가지 방법이 존재합니다. 본인은 1번 선택
1 . SwaggerBody 커스텀 어노테이션(springdoc-openapi 2.3 버전 출시에 따른 사용가능)
- 목적: Swagger 문서에서 multipart 요청의 JSON 데이터 파트에 대해 올바른 encoding 정보를 추가하여,Swagger UI에서 "Try it out" 시 해당 파트의 Content-Type을 application/json으로 지정함
- 적용 대상:
- JSON 데이터와 파일을 동시에 보내는 API
- Swagger UI 내에서 JSON 파트의 Content-Type이 올바르게 설정되지 않는 문제 해결
2. MultipartJackson2HttpMessageConverter 도입
- 목적: 클라이언트(또는 Swagger UI)에서 JSON 파트가 잘못된 Content-Type(기본값: application/octet-stream)으로 전송되어도 서버가 이를 변환하려고 시도하지 않도록 하여, 415 오류를 우회하는 해결책
- 동작 원리:
- AbstractJackson2HttpMessageConverter를 상속하여,
- application/octet-stream Content-Type에 대해 변환이 시도되지 않도록 오버라이딩
- 주의사항: 이 방법은 근본적으로 클라이언트에서 올바른 Content-Type(application/json)을 설정하도록 하는 것이 최선이나, Swagger UI 테스트나 임시 환경에서는 잘못된 Content-Type으로 인한 문제를 회피할 수 있는 우회책으로 사용
코드 적용 및 결과
코드 적용
Gradle
- 주의사항: springdoc 버전 2.3이상으로 사용!!!
// swagger
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0'
SwaggerBody
- 어노테이션 대신 별도 생성 이유: 어노테이션으로 하면 Swagger의 어노테이션 RequestBody와 Spring controller의 RequestBody 어노테이션이랑 겹침, 따라서 명을 변경해줘야함, custom interface 생성
package com.example.lettering.util;
import io.swagger.v3.oas.annotations.extensions.Extension;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import org.springframework.core.annotation.AliasFor;
import java.lang.annotation.*;
/*
* 생성 이유: Swagger에서 Mutipart formdata 형식 업로드 가능하게 하기 위한 Custom Swagger Body
* 순서: Swagger의 RequestBody를 사용해야지만 가능 -> Controller에서 Spring의 RequestBody이름과 겹침 따라서 별도의 Custom 생성 후 이름 변경 필요
* */
@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@RequestBody
public @interface SwaggerBody {
@AliasFor(annotation = RequestBody.class)
String description() default "";
@AliasFor(annotation = RequestBody.class)
Content[] content() default {};
@AliasFor(annotation = RequestBody.class)
boolean required() default false;
@AliasFor(annotation = RequestBody.class)
Extension[] extensions() default {};
@AliasFor(annotation = RequestBody.class)
String ref() default "";
}
Controller API 일부 작성
- Swagger Custom RequestBody인 SwaggerBody 언급
@Operation(summary = "실링왁스 등록 기능", description = "실링왁스 디자인을 추가합니다.")
@SwaggerBody(content = @Content(encoding = @Encoding(name = "sealingwax", contentType = MediaType.APPLICATION_JSON_VALUE)))
@PostMapping(value = "/backoffice", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<SealingWaxResponse> createSealingWax(
@RequestPart("sealingwax") CreateSealingWaxRequest createSealingWaxRequest,
@RequestPart("image") MultipartFile imageFile) throws IOException {
return ResponseEntity.ok(sealingWaxService.createSealingWax(createSealingWaxRequest, imageFile));
}
결과
- type= applicaton/json 잘 적용된 모습
출처
2.3 · Releases · springdoc/springdoc-openapi
Releases · springdoc/springdoc-openapi
Library for OpenAPI 3 with spring-boot. Contribute to springdoc/springdoc-openapi development by creating an account on GitHub.
github.com
Swagger(스웨거) multipart/form-data에서 try out이 불가능한 문제 "Content-Type 'application/octet-stream' is not supp
개요 평소 API 문서 자동화 프레임워크로 `Swagger`를 많이 써왔는데 `multipart/form-data`를 Body로 받는 API의 경우 `Swagger` 문서에서 try out(실행)할 시에 예외(HttpMediaTypeNotSupportedException)가 발생하는 문제
aahc912.tistory.com
'스프링' 카테고리의 다른 글
[AI] 이미지 생성시 DALLE에서 Stable Diffusion으로 AI모델 변경 with SpringAI (2) | 2025.02.02 |
---|---|
AWS S3와 IAM 생성: 스프링과의 연동 방법 및 이미지 저장 (0) | 2024.03.20 |
[Spring] Validation 종류 및 적용 (0) | 2024.03.15 |
[스프링] 스프링 3.1이후에 디버그 로그가 안뜰경우, 로그레벨 조정 방법 (0) | 2024.01.29 |
[스프링] 혼자 구현하는 웹 서비스1: 프로젝트 세팅 (0) | 2024.01.08 |