[Spring MVC+WebClient -> FastAPI] 422 UNPROCESSABLE_ENTITY

강효진·2023년 4월 2일
0

Error

목록 보기
2/2

오류 발생 코드

	public DinosaurNameDto getRecommendedDinosaurName(FileDto fileDto) {
		MultipartBodyBuilder builder = new MultipartBodyBuilder();

		// Add file part
		Resource image = fileDto.getFile().getResource();
		builder.part("file", image);

		// Build and use
		MultiValueMap<String, HttpEntity<?>> multipartBody = builder.build();

		return webClient.post()
			.uri("/v1/....")
			.accept(MediaType.APPLICATION_JSON)
			.contentType(MediaType.MULTIPART_FORM_DATA)
			//.body(BodyInserters.fromMultipartData(multipartBody))
            .bodyValue(multipartBody)
			.retrieve()
			.bodyToMono(xxx.class)
			.onErrorResume(WebClientResponseException.class,
				ex -> ex.getStatusCode().value() == 404 ? Mono.empty() : Mono.error(ex))
			.block();
	}

에러 메세지

2023-04-03T00:23:51.998+09:00 ERROR 25196 --- [nio-8086-exec-2] c.s.d.a.e.GlobalExceptionHandler         : handleGlobalException
org.springframework.web.reactive.function.client.WebClientResponseException$UnprocessableEntity: 422 Unprocessable Entity from POST http://............
	at org.springframework.web.reactive.function.client.WebClientResponseException.create(WebClientResponseException.java:329)
	Suppressed: The stacktrace has been enhanced by Reactor, refer to additional information below: 
Error has been observed at the following site(s):
	*__checkpoint ⇢ 422 UNPROCESSABLE_ENTITY from POST http://.......... [DefaultWebClient]
Original Stack Trace:
		at ............
	Suppressed: java.lang.Exception: #block terminated with an error
		at ............

고민, 조사

422 Error code에 대해 검색을 해봤는데, FastAPI 환경에서 이 오류를 마주했다는 글을 보게 되었다. 그래서 그쪽으로 고민하기 시작했다.


문제 발생 가능성 추론

  1. Spring 서버 쪽(Client)의 문제 or FastAPI 서버 쪽(Server)의 문제?
    ➡️ 4xx 오류이므로 요청하는 Spring 서버 쪽(Client)의 문제다.
  1. 그렇다면 어느 부분에서?
    1) uri 부분 ❌

    uri("/v1/....")

    ➡️ 꼼꼼히 봤는데 틀린 부분이 없었음.

    2) accept 부분 ❌

    .accept(MediaType.APPLICATION_JSON)

    ➡️ 사실 처음에 뭔지 모르고 막 쓰다가 accepct 부분에 MediaType.MULTIPART_FORM_DATA를 써놨었음. 근데 이건 문제가 없었음.

    3) contentType 부분 ❌

    .contentType(MediaType.MULTIPART_FORM_DATA)

    ➡️ 이건 틀릴 리가 없는데 내가 accept랑 반대로 썼나? 헷갈릴 정도로 도저히 틀린 부분을 못찾겠는 상태였음.....

    4) body 부분 ❌

    //.body(BodyInserters.fromMultipartData(multipartBody))
     .bodyValue(multipartBody)

    ➡️ 원래 밑의 코드로 작성했었는데 하도 틀린 부분을 못찾겠어서 블로그 검색 코드로 바꿔봤음. 근데 역시나 이건 문제가 아님.

    5) MultipartBodyBuilder 부분 ⭕

    MultipartBodyBuilder builder = new MultipartBodyBuilder();
    
    // Add file part
    Resource image = fileDto.getFile().getResource();
    builder.part("file", image);
    
    // Build and use
    MultiValueMap<String, HttpEntity<?>> multipartBody = builder.build();

    ➡️ 이것도 원래 이 코드였는데 하도 안 돼서 블로그 검색 코드(byte 배열 이용하고 header 설정해주고 하는,,)로 바꿔봤으나.... 똑같았다.
    근데 !! 생각해보니 Server 쪽에선 "file"이 아니라 "image"로 받고 있던 거였음 ㅜㅜ


결론, 해결

Resource image = fileDto.getFile().getResource();
builder.part("file", image);

⬇️

Resource image = fileDto.getFile().getResource();
builder.part("image", image);

공식 API Reference (RestDoc)만 보고 그대로 따라해도 문제 없는 게 맞았음.
그냥 Server 쪽의 request parameter 이름이 일치하지 않는 단순 실수인데 엄한 데에서 원인을 찾으려고 했다

profile
짱발자가 될 거야 🔥🔥🔥

0개의 댓글