본문 바로가기
WIKI 기술 지식 베이스

route 지시문

원문 보기 위키 갱신

route 지시문 (그룹을 그대로 평가)

route 지시문은 지시문 그룹을 문자 그대로, 하나의 단위로 평가해요. route 블록 안의 지시문은 내부적으로 재정렬되지 않아요.

출처: Caddy 공식 문서

본문

지시문 그룹을 문자 그대로, 하나의 단위로 평가해요.

route 블록에 포함된 지시문은 내부적으로 재정렬되지 않아요. route 블록에는 HTTP 핸들러 지시문(체인에 핸들러나 미들웨어를 추가하는 지시문)만 사용할 수 있어요.

이 지시문은 하위 지시문도 일반 지시문이라는 점에서 특별한 경우예요.

문법 (Syntax)

route [<matcher>] {
	<directives...>
}
  • **<directives...>**는 route 블록 밖과 마찬가지로 한 줄에 하나씩 나열하는 지시문 또는 지시문 블록 목록이에요. 단, 이 지시문들은 재정렬되지 않아요. HTTP 핸들러 지시문만 사용할 수 있어요.

유용성 (Utility)

route 지시문은 HTTP 핸들러 체인의 일부를 절대적으로 제어해야 하는 특정 고급 사용 사례나 엣지 케이스에서 유용해요.

HTTP 미들웨어 평가 순서는 중요하기 때문에, Caddyfile은 보통 파싱 후 지시문을 재정렬해 Caddyfile을 더 쉽게 사용하게 해줘요. 입력한 순서에 신경 쓸 필요가 없어요.

내장 순서가 대부분의 사이트와 호환되지만, 때로는 사이트 전체든 일부든 순서를 수동으로 제어해야 할 때가 있어요. 그럴 때 쓰는 게 route 지시문이에요.

예를 들어 두 종료(terminating) 핸들러를 생각해볼게요: redir와 file_server. 둘 다 응답을 클라이언트에 쓰고 체인의 다음 핸들러를 호출하지 않아서, 특정 요청에는 하나만 실행돼요. 그러면 어느 것이 먼저 올까요? 보통 redir가 file_server보다 먼저 실행돼요. 대부분 특정 경우에만 리다이렉트하고 일반 경우에는 파일을 서빙하고 싶기 때문이에요.

하지만 첫 번째 지시문(file_server)의 matcher가 두 번째(redir)보다 더 구체적인 경우가 있을 수 있어요. 즉 일반 경우에는 리다이렉트하고, 특정 파일만 서빙하고 싶은 거예요.

그래서 이렇게 Caddyfile을 시도할 수 있지만(예상대로 동작하지 않을 거예요!):

example.com {
	file_server /specific.html
	redir https://anothersite.com{uri}
}

문제는 지시문이 정렬된 후에 redir가 file_server보다 앞에 온다는 거예요.

하지만 이 경우 redir의 matcher(암시적 *)는 file_server의 matcher(*가 /specific.html의 상위 집합)의 상위 집합이에요.

다행히 해결책은 간단해요. 그 두 지시문을 route 블록으로 감싸면 file_server가 redir보다 먼저 실행되도록 보장돼요:

example.com {
	route {
		file_server /specific.html
		redir https://anothersite.com{uri}
	}
}

또 다른 방법은 두 matcher를 상호 배타적으로 만드는 거지만, 조건이 한두 개보다 많으면 빠르게 복잡해질 수 있어요. route 지시문으로는 두 핸들러가 모두 종료 핸들러라서 그 상호 배타성이 암시적이에요.

이제 순서가 문자 그대로 받아들여지므로 file_server가 redir보다 먼저 체인에 들어가요.

비슷한 지시문 (Similar directives)

HTTP 핸들러 지시문을 감쌀 수 있는 다른 지시문도 있는데, 전달하려는 동작에 따라 각각 용도가 달라요:

  • handle은 route처럼 다른 지시문을 감싸는데 두 가지 차이가 있어요: 1) handle 블록은 서로 상호 배타적이고, 2) handle 안의 지시문은 정상적으로 재정렬돼요.

  • handle_path는 handle과 동일하지만, 핸들러를 실행하기 전에 요청에서 접두사를 제거해요.

  • handle_errors는 handle과 비슷하지만, 요청 처리 중 Caddy가 에러를 만났을 때만 호출돼요.

예시 (Examples)

/api 요청은 그대로 프록시하고, 그 외 요청은 파일 일치 여부에 따라 재작성하되 그 외엔 /index.html로 재작성해요. 그다음 해당 파일을 서빙해요.

try_files는 reverse_proxy보다 지시문 순서가 높아서 보통 더 높게 정렬되어 먼저 실행돼요. 이러면 API 요청이 모두 /index.html로 재작성되어 /api*와 일치하지 않게 되고, 어떤 요청도 프록시되지 않아 대신 file_server에서 404가 나요. 전부 route로 감싸면 reverse_proxy가 요청이 재작성되기 전에 항상 먼저 실행되도록 보장돼요.

example.com {
	root /srv
	route {
		reverse_proxy /api* localhost:9000

		try_files {path} /index.html
		file_server
	}
}

이 문제의 유일한 해결책은 아니에요. handle 블록 한 쌍을 사용할 수도 있는데, 첫 번째가 /api*를 reverse_proxy에 매칭하고 두 번째가 폴백 역할을 하며 파일을 서빙해요. SPA의 이 예시를 참고해요.

더 알아보기 (Learn more)