본문 바로가기
버그일기

[spring boot] 비동기 처리와 response 500 에러

by xunxou 2023. 1. 13.

비동기처리 중 500 에러가 발생했습니다.

controller를 잘 호출하고, 서버에서도 에러없이 로직을 잘 처리하는데 계속 500에러가 발생했습니다.

저와 같은 상황이시면 해당 포스팅을 참고해보시면 좋겠습니다.

 

[상황]

1. 비동기 요청을 했을때 GetMapping의 경로대로 controller 메소드를 잘 탑니다.(비동기 처리, 경로이상X

2. 서버의 모든 로직을 에러없이 잘 처리합니다.(코드에러X)

3. 그럼에도 불구하고 서버 console에 템플릿이 존재하지 않거나 액세스 할 수 없다는 에러가 뜹니다.

Error resolving template [controller 경로], template might not exist or might not be accessible by any of the configured Template Resolvers

4. 브라우저에서 값을 추적했을때 response status:500을 반환하며 아래와 같은 에러가 브라우저 console창에서 확인됩니다.

GET http://.... 500
Uncaught (in promise)   (fetch함수에서의 error)

 

 

[html 코드]

fetch 함수를 이용해 http 요청을 전송합니다.

async function getJson(uri, params) {
    if (params) {
        uri = uri + "?" + new URLSearchParams(params).toString();
    }

    const response = await fetch(uri); // uri: /list?examVal1=a&examVal2=b

   ...
}

 

[controller 코드]

@GetMapping("/list")
public Map<String, Object> findAll(final ExamDTO examDTO) {
    Map<String, Object> listMap = service.findAll(examDTO);
    return listMap;
}

 

 

[해결]

Controller의 메소드에 @ResponseBody 어노테이션을 추가합니다.

이유를 설명하면 다음과 같습니다.

스프링에는 viewResolver라는 객체가 있습니다. 해당 객체는 전달받은 경로와 파일명을 통해 view를 찾아냅니다.

Controller에서 return하면 viewResolver 객체가 파일명과 경로를 DispatcherServlet으로 전달합니다.

그러면 templates 또는 static 폴더에서 해당 경로와 파일명을 찾아 응답합니다.

이때 @ResponseBody를 사용하면 viewResolver를 사용하지 않고, HTTP의 body에 그대로 결과값을 반환합니다.

현재 코드에서는 값을 그대로 반환해야하므로 @ResponseBody 를 사용해야합니다. 

@GetMapping("/list")
@ResponseBody
public Map<String, Object> findAll(final ExamDTO examDTO) {
    Map<String, Object> listMap = service.findAll(examDTO);
    return listMap;
}

 

또 다른 방법은 Controller에 @Controller 대신 @RestController 를 사용하는 것입니다.

@RestController 을 살펴보면 우리가 명시해주려던 @ResponseBody 가 포함돼있는것을 확인할 수 있습니다.

또한 @Controller 를 포함하고있기 때문에 '대신' 사용해야하지 '같이' 사용하면 안됩니다.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
...
}