본문으로 바로가기
TaeyoungKim.dev

Spring Boot 정적 콘텐츠와 Controller가 함께 있을 때 무엇이 먼저 동작할까?

자바/스프링작성 약 4분 읽기TaeyoungKim
LinkedInX

/welcome.html을 고쳤는데 브라우저에는 예전 문구가 남아 있다. 캐시 문제로 생각하기 전에 같은 URL을 처리하는 Controller가 있는지 확인해 보자. 정적 파일과 Controller가 정확히 같은 경로를 가리킬 때 어느 쪽 응답이 선택되는지 따라가면 원인이 보인다.

Controller 매핑은 요청을 가장 먼저 해석한다

일반적인 Spring Boot MVC 설정에서는 Controller 매핑이 정적 리소스 처리보다 먼저 선택된다. 아래 예제에는 src/main/resources/static/welcome.html 파일이 있고, Controller도 같은 /welcome.html에 응답한다고 가정한다.

두 응답을 구별하기 위해 Controller는 controller page, 정적 파일은 static page를 내보내게 한다.

java
@Controller
class WelcomeController {
    @GetMapping("/welcome.html")
    @ResponseBody
    String welcome() {
        return "controller page";
    }
}

@ResponseBody를 붙였으므로 이 문자열은 뷰 이름이 아니라 HTTP 본문이다. 같은 URL의 정적 파일이 있어도 이 매핑이 살아 있다면 /welcome.html의 응답 본문은 controller page다. 매핑을 제거하거나 경로를 바꾼 뒤 다시 요청해야 정적 파일의 static page를 볼 수 있다.

정적 파일은 매핑이 없을 때 후보가 된다

Controller 매핑이 없으면 Spring Boot의 정적 리소스 위치가 후보가 된다. src/main/resources/static 아래의 파일은 기본적으로 URL 경로와 연결된다.

text
src/main/resources/static/welcome.html
                 └── /welcome.html

이번에는 같은 /welcome.html 요청에서 Controller만 제거한 것이다. 응답이 static page로 바뀌면 파일이 없어졌던 게 아니라 앞선 매핑이 가리고 있었던 셈이다. 반면 /welcome은 다른 URL이므로 이 파일을 자동으로 가리킨다고 기대하면 안 된다.

충돌처럼 보일 때는 경로와 응답을 분리해 확인한다

처음에는 Controller와 정적 파일을 둘 다 두고 /welcome.html을 요청한다. 다음에는 Controller의 매핑만 제거하고 같은 URL을 다시 요청한다. 요청 경로까지 바꾸면 어느 설정 때문에 결과가 달라졌는지 판단하기 어렵다.

같은 요청 /welcome.html예상 본문먼저 확인할 곳
Controller 매핑 있음controller page해당 경로의 매핑과 @ResponseBody
Controller 매핑 제거static page정적 파일의 실제 위치와 이름

둘 다 기대와 다르면 요청 경로·프로파일별 설정·리소스 핸들러 설정을 확인한다. Controller가 뷰 이름을 반환하도록 바꾼 경우에는 @ResponseBody를 제거하고 템플릿 위치를 따로 확인해야 한다. 응답 본문과 뷰 이름은 같은 문자열이어도 다른 의미다.

경로 이름을 공유하지 않는 설계가 더 안전하다

정적 파일은 assets/, docs/처럼 성격이 드러나는 경로에 두고, 화면 진입점은 Controller URL로 정하면 유지보수가 편하다. 동일한 URL을 두 방식에 기대면 변경하는 사람은 매번 탐색 순서를 떠올려야 한다.

테스트에서도 '200이 왔다'만 보지 말고 기대한 본문 또는 뷰 이름을 확인한다.

java
mockMvc.perform(get("/welcome.html"))
    .andExpect(status().isOk())
    .andExpect(content().string("controller page"));

이 테스트는 Controller 매핑이 있는 설정에서만 기대한 결과다. 매핑을 제거한 경우에는 별도 테스트에서 static page가 나오는지 확인한다. 정적 콘텐츠는 파일을 제공하는 데 알맞고, Controller는 입력 검증·데이터 조회·권한처럼 요청별 판단이 필요할 때 알맞다. 같은 URL을 두 책임에 동시에 맡기지 않는 편이 안전하다.

핵심 요약

같은 /welcome.html 요청에 Controller 매핑이 있으면 그 메서드가 먼저 응답하고, 매핑을 없애면 정적 파일이 후보가 된다. 두 경우의 응답 문구를 구별해 확인하자. /welcome은 별도 URL이며, 정적 자산과 동적 화면의 경로를 의도적으로 나누면 이런 충돌을 피하기 쉽다.

작성자

TaeyoungKim

기초 개념을 구현과 검증, 실제 운영 판단까지 연결해 기록합니다.

#Spring Boot#Controller#정적 콘텐츠#MVC

함께 읽으면 좋은 글