요청 매처
요청 매처 (Request Matchers)
출처: Caddy 공식 문서
본문
**요청 매처(request matcher)**는 다양한 기준으로 요청을 필터링(또는 분류)하는 데 사용할 수 있어요.
구문
Caddyfile에서 지시문 바로 뒤에 오는 **매처 토큰(matcher token)**이 그 지시문의 범위를 제한할 수 있어요. 매처 토큰은 다음 형태 중 하나일 수 있어요:
지시문이 매처를 지원하면 구문 문서에 [<matcher>]로 나타나요. 매처 토큰은 보통 선택적이며 [ ]로 표시돼요. 매처 토큰을 생략하면 와일드카드 매처(*)와 같아요.
예제
이 지시문은 모든 HTTP 요청에 적용돼요:
reverse_proxy localhost:9000
그리고 이것도 같아요(여기서 *는 불필요해요):
reverse_proxy * localhost:9000
하지만 이 지시문은 /api/로 시작하는 경로를 가진 요청에만 적용돼요:
reverse_proxy /api/* localhost:9000
경로가 아닌 다른 것으로 일치시키려면 명명된 매처를 정의하고 @name으로 참조해요:
@postfoo {
method POST
path /foo/*
}
reverse_proxy @postfoo localhost:9000
와일드카드 매처
와일드카드(또는 "catch-all") 매처 *는 모든 요청을 일치시키며, 매처 토큰이 필요할 때만 쓰면 돼요. 예를 들어 지시문에 주고 싶은 첫 번째 인수가 우연히 경로라면, 그것이 정확히 경로 매처처럼 보일 거예요! 그래서 와일드카드 매처로 구별할 수 있어요. 예:
root * /home/www/mysite
그 외에는 이 매처를 자주 사용하지 않아요. 구문이 요구하지 않는다면 생략하는 것을 일반적으로 권장해요.
경로 매처
URI 경로로 일치시키는 것이 요청을 일치시키는 가장 흔한 방법이라 매처를 인라인할 수 있어요. 이렇게:
redir /old.html /new.html
경로 매처 토큰은 슬래시 /로 시작해야 해요.
경로 일치는 기본적으로 접두사 일치가 아니라 정확 일치예요. 빠른 접두사 일치를 위해 *를 붙여야 해요. /foo*는 /foo와 /foo/뿐 아니라 /foobar도 일치시킨다는 점을 주의하세요. 아마 실제로 /foo/*를 원할 거예요.
명명된 매처
경로나 와일드카드가 아닌 모든 매처는 명명된 매처여야 해요. 이는 특정 지시문 밖에서 정의되고 재사용할 수 있는 매처예요.
고유한 이름으로 매처를 정의하면 더 많은 유연성을 얻어 사용 가능한 매처를 집합으로 결합할 수 있어요:
@name {
...
}
또는 집합에 매처가 하나뿐이라면 같은 줄에 둘 수 있어요:
@name ...
그럼 지시문의 첫 번째 인수로 지정해 이렇게 매처를 사용할 수 있어요:
directive @name
예를 들어 이렇게 하면 HTTP/1.1 웹소켓 요청을 localhost:6001로 프록시하고 다른 요청은 localhost:8080으로 프록시해요. Connection이라는 이름의 헤더 필드가 Upgrade를 포함하고 그리고 Upgrade라는 필드가 정확히 websocket인 요청을 일치시켜요:
example.com {
@websockets {
header Connection *Upgrade*
header Upgrade websocket
}
reverse_proxy @websockets localhost:6001
reverse_proxy localhost:8080
}
매처 집합이 매처 하나만으로 구성되면 한 줄 구문도 동작해요:
@post method POST
reverse_proxy @post localhost:6001
특수한 경우로 expression매처는 매처 이름 뒤에 따옴표로 묶인 인수(CEL 표현식 자체) 하나가 오는 한 이름을 지정하지 않고 사용할 수 있어요:
@not-found `{err.status_code} == 404`
지시문처럼 명명된 매처 정의는 그것을 사용하는 사이트 블록 안에 있어야 해요.
명명된 매처 정의는 매처 집합을 구성해요. 집합의 매처들은 AND로 결합돼요. 즉 모두 일치해야 해요. 예를 들어 집합에 header와 path 매처가 모두 있으면 둘 다 일치해야 해요.
같은 타입의 여러 매처는 아래 각 섹션에 설명된 대로 부울 대수(AND/OR)를 사용해 병합될 수 있어요(예: 같은 집합의 여러 path 매처).
더 복잡한 부울 일치 로직을 위해서는 expression매처로 CEL 표현식을 작성하는 것을 권장해요. 이는 and &&, or ||, 괄호 ( )를 지원해요.
표준 매처
전체 매처 문서는 각 매처 모듈의 문서에서 찾을 수 있어요.
요청은 다음과 같은 방법으로 일치시킬 수 있어요:
client_ip
client_ip <ranges...>
expression client_ip('<ranges...>')
클라이언트 IP 주소로. 정확한 IP나 CIDR 범위를 받아요. IPv6 zone이 지원돼요.
이 매처는 trusted_proxies 전역 옵션이 구성되었을 때 가장 잘 사용돼요. 그렇지 않으면 remote_ip 매처와 동일하게 동작해요. 신뢰된 프록시의 요청만 요청 시작 시 클라이언트 IP가 파싱되고, 신뢰되지 않은 요청은 직접 피어의 리모트 IP 주소나 PROXY 프로토콜로 설정된 주소를 사용해요.
지름길로 private_ranges를 사용해 모든 사설 IPv4 및 IPv6 범위를 일치시킬 수 있어요. 다음 모든 범위를 지정하는 것과 같아요: 192.168.0.0/16 172.16.0.0/12 10.0.0.0/8 127.0.0.1/8 fd00::/8 ::1
명명된 매처마다 client_ip 매처가 여러 개 있을 수 있고, 그 범위는 병합되어 OR로 결합돼요.
예제:
사설 IPv4 주소의 요청 일치:
@private-ipv4 client_ip 192.168.0.0/16 172.16.0.0/12 10.0.0.0/8 127.0.0.1/8
이 매처는 일치를 반전시키기 위해 not 매처와 자주 짝을 이뤄요. 예를 들어 공개 IPv4 및 IPv6 주소(모든 사설 범위의 반대)의 모든 연결을 중단하려면:
example.com {
@denied not client_ip private_ranges
abort @denied
respond "Hello, you must be from a private network!"
}
CEL 표현식에서는 이렇게 보여요:
@my-friends `client_ip('12.23.34.45', '23.34.45.56')`
expression
expression <cel...>
true나 false를 반환하는 모든 CEL (Common Expression Language) 표현식으로.
대부분의 다른 요청 매처는 표현식 안에서 함수로도 사용할 수 있어, 표현식 밖보다 부울 로직에 더 많은 유연성을 제공해요. CEL 표현식 안에서 지원되는 구문은 각 매처의 문서를 참고하세요.
Caddy 플레이스홀더(또는 Caddyfile 약어)는 CEL 환경이 해석하기 전에 전처리되어 일반 CEL 함수 호출로 변환되므로 이러한 CEL 표현식에서 사용할 수 있어요. 플레이스홀더를 매처 함수에 문자열 인수로 전달해야 한다면 전처리되지 않도록 앞 {를 백슬래시 \\로 이스케이프해야 해요. 예: file('\\{path}.md').
편의상, 순수하게 CEL 표현식으로 구성된 명명된 매처를 정의할 때 매처 이름을 생략할 수 있어요. CEL 표현식은 따옴표로 묶어야 해요(백틱이나 heredoc 권장). 이렇게 읽기가 꽤 좋아요:
@mutable `{method}.startsWith("P")`
이 경우 CEL 매처가 가정돼요.
예제:
메서드가 P로 시작하는 요청 일치, 예: PUT 또는 POST:
@methods expression {method}.startsWith("P")
핸들러가 오류 상태 코드 404를 반환한 요청 일치. handle_errors지시문과 함께 사용돼요:
@404 expression {err.status_code} == 404
경로가 두 개의 서로 다른 정규식 중 하나와 일치하는 요청을 일치. path_regexp 매처는 보통 명명된 매처당 한 번만 존재할 수 있기 때문에 표현식으로만 작성할 수 있어요:
@user expression path_regexp('^/user/(\w*)') || path_regexp('^/(\w*)')
또는 매처 이름을 생략하고 백틱으로 감싸 단일 토큰으로 파싱되게 해서 같은 것:
@user `path_regexp('^/user/(\w*)') || path_regexp('^/(\w*)')`
heredoc 구문을 사용해 여러 줄 CEL 표현식을 작성할 수 있어요:
@api <<CEL
{method} == "GET"
&& {path}.startsWith("/api/")
CEL
respond @api "Hello, API!"
file
file {
root <path>
try_files <files...>
try_policy first_exist|first_exist_fallback|smallest_size|largest_size|most_recently_modified
split_path <delims...>
}
file <files...>
expression `file({
'root': '<path>',
'try_files': ['<files...>'],
'try_policy': 'first_exist|first_exist_fallback|smallest_size|largest_size|most_recently_modified',
'split_path': ['<delims...>']
})`
expression file('<files...>')
파일로.
root는 파일을 찾을 디렉터리를 정의해요. 기본은 현재 작업 디렉터리이거나, 설정된 경우 root 변수({http.vars.root})예요(root지시문으로 설정 가능).
try_files는 try_policy와 일치하는 목록의 파일을 확인해요.
디렉터리를 일치시키려면 경로 끝에 슬래시 /를 추가하세요. 모든 파일 경로는 사이트 root 기준이며, glob 패턴이 확장돼요.
try_policy가 first_exist(기본)라면 목록의 마지막 항목은 = 접두사가 붙은 숫자(예: =404)일 수 있으며, 폴백으로 그 코드의 오류를 발생시키고, 이 오류는 handle_errors로 잡아 처리할 수 있어요.
try_policy는 파일을 선택하는 방법을 지정해요. 기본은 first_exist예요.
first_exist는 파일 존재를 확인해요. 존재하는 첫 번째 파일이 선택돼요.
first_exist_fallback는 first_exist와 유사하지만, 디스크 접근을 막기 위해 목록의 마지막 요소가 항상 존재한다고 가정해요.
smallest_size는 가장 작은 크기의 파일을 선택해요.
largest_size는 가장 큰 크기의 파일을 선택해요.
most_recently_modified는 가장 최근에 수정된 파일을 선택해요.
split_path는 시도할 각 파일 경로에서 발견된 목록의 첫 번째 구분자에서 경로를 분할하게 해요. 각 분할 값에 대해 분할 왼쪽(구분자 자체 포함)이 시도되는 파일 경로예요. 예를 들어 /.php 구분자를 사용하는 /remote.php/dav/는 /remote.php 파일을 시도해요. 각 구분자는 분할 구분자로 사용되려면 URI 경로 구성 요소 끝에 나타나야 해요. 이는 틈새 설정이며 PHP 사이트를 서빙할 때 주로 사용돼요.
first_exist 정책의 try_files가 매우 흔하기 때문에 그에 대한 한 줄 지름길이 있어요:
file <files...>
빈 file 매처(그 뒤에 나열된 파일이 없는 것)는 요청된 파일—URI에서 그대로, 사이트 루트 기준—이 존재하는지 확인해요. 이는 실질적으로 file {path}와 같아요.
디스크의 파일 존재에 기반한 재작성이 매우 흔하기 때문에 file 매처와 rewrite핸들러의 지름길인 try_files지시문도 있어요.
일치 시 4개의 새 플레이스홀더가 사용 가능해져요:
-
{file_match.relative}파일의 루트 기준 경로예요. 요청을 재작성할 때 종종 유용해요. -
{file_match.absolute}일치한 파일의 절대 경로로, 루트를 포함해요. -
{file_match.type}파일의 타입,file또는directory. -
{file_match.remainder}파일 경로를 분할한 후 남은 부분(split_path가 구성된 경우)
예제:
경로가 존재하는 파일인 요청 일치:
@file file
경로 뒤에 .html을 붙인 것이 존재하는 파일이거나, 아니면 경로가 존재하는 파일인 요청 일치:
@html file {
try_files {path}.html {path}
}
한 줄 지름길을 사용하고 파일을 찾지 못하면 404 오류를 내보내는 폴백을 하는 점을 제외하면 위와 같음:
@html-or-error file {path}.html {path} =404
CEL 표현식을 사용하는 몇 가지 예제 더. 플레이스홀더는 CEL 환경이 해석하기 전에 전처리되어 일반 CEL 함수 호출로 변환된다는 점을 명심하세요. 그래서 여기서 연결(concatenation)을 사용해요. 추가로 현재 파싱 제한 때문에 플레이스홀더와 연결할 때는 긴 형식(long-form)을 사용해야 해요:
@file `file()`
@first `file({'try_files': [{path}, {path} + '/', 'index.html']})`
@smallest `file({'try_policy': 'smallest_size', 'try_files': ['a.txt', 'b.txt']})`
header
header <field> [<value>]
expression header({'<field>': '<value>'})
요청 헤더 필드로.
-
<field>는 확인할 HTTP 헤더 필드의 이름이에요. -
!로 접두사가 붙으면 일치하려면 필드가 존재하지 않아야 해요(값 인수 생략). -
<value>는 일치하려면 필드가 가져야 하는 값이에요. -
*로 접두사가 붙으면 빠른 접미사 일치를 수행해요(끝에 나타남). -
*로 접미사가 붙으면 빠른 접두사 일치를 수행해요(시작에 나타남). -
*로 둘러싸이면 빠른 부분 문자열 일치를 수행해요(어디든 나타남). -
그렇지 않으면 빠른 정확 일치예요.
같은 집합 내의 다른 헤더 필드는 AND로 결합돼요. 같은 필드에 여러 값을 일치시키려면 같은 매처 집합 내에 값별로 header 매처를 하나씩 지정하세요. 그 값들은 OR로 결합돼요.
헤더 필드는 반복될 수 있고 다른 값을 가질 수 있다는 점을 주의하세요. 백엔드 애플리케이션은 헤더 필드 값이 단일 값이 아니라 배열임을 고려해야 하며, Caddy는 그런 난해함에 의미를 부여하지 않아요.
예제:
Connection 헤더가 Upgrade를 포함하는 요청 일치:
@upgrade header Connection *Upgrade*
Foo 헤더가 bar 또는 baz를 포함하는 요청 일치:
@foo {
header Foo bar
header Foo baz
}
Foo 헤더 필드가 전혀 없는 요청 일치:
@not_foo header !Foo
CEL 표현식을 사용해 Connection 헤더가 Upgrade를 포함하고 Upgrade 헤더가 websocket과 같은 웹소켓 요청 일치(HTTP/2는 이를 위해 :protocol 헤더가 있음):
@websockets `header({'Connection':'*Upgrade*','Upgrade':'websocket'}) || header({':protocol': 'websocket'})`
header_regexp
header_regexp [<name>] <field> <regexp>
expression header_regexp('<name>', '<field>', '<regexp>')
expression header_regexp('<field>', '<regexp>')
사용되는 정규식 언어는 Go에 포함된 RE2예요. RE2 구문 참조와 Go regexp 구문 개요를 참고하세요.
v2.8.0부터 name을 제공하지 않으면 이름은 명명된 매처의 이름에서 가져와요. 예를 들어 명명된 매처 @foo는 이 매처가 foo로 이름지어지게 해요. 이름을 지정하는 주된 이점은 같은 명명된 매처에서 둘 이상의 regexp 매처(예: header_regexp와 path_regexp, 또는 여러 다른 헤더 필드)를 사용할 때예요.
캡처 그룹은 일치 후 플레이스홀더로 지시문에서 접근할 수 있어요:
{re.<name>.<capture_group>} 여기서:
-
<name>은 정규식의 이름이고, -
<capture_group>은 표현식의 캡처 그룹의 이름이나 번호예요.
이름 없는 {re.<capture_group>}도 편의를 위해 채워져요. 단, 여러 regexp 매처가 순차적으로 사용되면 플레이스홀더 값이 다음 매처에 의해 덮어써진다는 주의가 있어요.
캡처 그룹 0은 전체 regexp 일치, 1은 첫 번째 캡처 그룹, 2는 두 번째 캡처 그룹 등이에요. 그래서 {re.foo.1} 또는 {re.1} 모두 첫 번째 캡처 그룹의 값을 담아요.
regexp 패턴은 병합될 수 없으므로 헤더 필드당 정규식 하나만 지원돼요. 더 필요하면 expression매처를 사용하는 것을 고려해보세요. 여러 다른 헤더 필드에 대한 일치는 AND로 결합돼요.
예제:
Cookie 헤더가 login_ 뒤에 16진수 문자열이 오는 것을 포함하고, {re.login.1} 또는 {re.1}로 접근할 수 있는 캡처 그룹이 있는 요청 일치:
@login header_regexp login Cookie login_([a-f0-9]+)
명명된 매처에서 추론될 이름을 생략해 단순화할 수 있어요:
@login header_regexp Cookie login_([a-f0-9]+)
CEL 표현식을 사용한 같은 것:
@login `header_regexp('login', 'Cookie', 'login_([a-f0-9]+)')`
host
host <hosts...>
expression host('<hosts...>')
요청의 Host 헤더 필드로 요청을 일치시켜요.
대부분의 사이트 블록은 이미 사이트 주소에 호스트를 나타내므로, 이 매처는 와일드카드 호스트 이름을 사용하는 사이트 블록(와일드카드 인증서 패턴](/docs/caddyfile/patterns#wildcard-certificates) 참고)에서 호스트 이름별 로직이 필요할 때 더 흔히 사용돼요.
여러 host 매처는 OR로 결합돼요.
예제:
하나의 서브도메인 일치:
@sub host sub.example.com
에이펙스 도메인과 서브도메인 일치:
@site host example.com www.example.com
CEL 표현식을 사용한 여러 서브도메인:
@app `host('app1.example.com', 'app2.example.com')`
method
method <verbs...>
expression method('<verbs...>')
HTTP 요청의 메서드(동사)로. 하나 또는 많은 메서드를 일치시킬 수 있어요. 동사는 대문자로 변환되므로 대소문자를 구분하지 않아요. 그래서 post는 POST와 같아요. 하지만 CEL 표현식 안에서는 동사가 대문자여야 해요.
여러 method 매처는 OR로 결합돼요.
예제:
GET 메서드의 요청 일치:
@get method GET
PUT 또는 DELETE 메서드의 요청 일치:
@put-delete method PUT DELETE
CEL 표현식을 사용한 읽기 전용 메서드 일치:
@read `method('GET', 'HEAD', 'OPTIONS')`
not
not <matcher>
또는 AND로 결합되는 여러 매처를 부정하려면 블록을 열어요:
not {
<matchers...>
}
둘러싼 매처의 결과는 부정돼요.
예제:
/css/ 또는 /js/로 시작하지 않는 경로의 요청 일치:
@not-assets {
not path /css/* /js/*
}
NEITHER를 가진 요청 일치:
/api/경로 접두사도 아니고,POST요청 메서드도 아닌
즉 일치하려면 이들 중 어느 것도 가져서는 안 됨:
@with-neither {
not path /api/*
not method POST
}
BOTH가 없는 요청 일치:
/api/경로 접두사도 아니고,POST요청 메서드도 아닌
즉 일치하려면 이들 중 둘 다 없거나 하나만 가져야 함:
@without-both {
not {
path /api/*
method POST
}
}
이 매처에는 CEL 표현식이 없어요. 부정에 ! 연산자를 사용할 수 있기 때문이에요. 예:
@without-both `!path('/api*') && !method('POST')`
괄호를 사용하는 이것과 같아요:
@without-both `!(path('/api*') || method('POST'))`
path
path <paths...>
expression path('<paths...>')
요청 경로(요청 URI의 경로 구성 요소)로. 경로 일치는 정확하지만 대소문자를 구분하지 않아요. 와일드카드 *를 사용할 수 있어요:
-
끝에만, 접두사 일치용 (
/prefix/*) -
시작에만, 접미사 일치용 (
*.suffix) -
양쪽에만, 부분 문자열 일치용 (
*/contains/*) -
중간에만, glob 일치용 (
/accounts/*/info)
슬래시는 중요해요. 예를 들어 /foo*는 /foo, /foobar, /foo/, /foo/bar와 일치하지만, /foo/*는 /foo나 /foobar와 일치하지 않아요.
일치 전에 디렉터리 이동 점을 해결하도록 요청 경로가 정리돼요. 또한 일치 패턴에 여러 슬래시가 없으면 여러 슬래시가 병합돼요. 즉 /foo는 /foo와 //foo와 일치하지만, //foo는 //foo와만 일치해요.
주어진 URI에는 이스케이프 형태가 여러 가지 있기 때문에, 일치 패턴에도 이스케이프 시퀀스가 있는 위치를 제외하고 요청 경로는 정규화(URL 디코드, 이스케이프 해제)돼요. 예를 들어 /foo/bar는 /foo/bar와 /foo%2Fbar 모두와 일치하지만, /foo%2Fbar는 이스케이프 시퀀스가 구성에 명시적으로 주어져 있으므로 /foo%2Fbar와만 일치해요.
특수 와일드카드 이스케이프 %*를 * 대신 사용해 일치 범위를 이스케이프된 상태로 둘 수 있어요. 예를 들어 /bands/*/*는 /bands/AC%2FDC/T.N.T와 일치하지 않는데, 경로가 /bands/AC/DC/T.N.T처럼 보이는 정규화된 공간에서 비교되어 패턴과 일치하지 않기 때문이에요. 하지만 /bands/%*/*는 %*가 나타내는 범위가 이스케이프 시퀀스를 디코딩하지 않고 비교되므로 /bands/AC%2FDC/T.N.T와 일치해요.
여러 경로는 OR로 결합돼요.
예제:
여러 디렉터리와 그 내용 일치:
@assets path /js/* /css/* /images/*
특정 파일 일치:
@favicon path /favicon.ico
파일 확장자 일치:
@extensions path *.js *.css
CEL 표현식 사용:
@assets `path('/js/*', '/css/*', '/images/*')`
path_regexp
path_regexp [<name>] <regexp>
expression path_regexp('<name>', '<regexp>')
expression path_regexp('<regexp>')
path와 같지만 정규식을 지원해요. URI 디코드/이스케이프 해제된 경로에 대해 실행돼요.
사용되는 정규식 언어는 Go에 포함된 RE2예요. RE2 구문 참조와 Go regexp 구문 개요를 참고하세요.
v2.8.0부터 name을 제공하지 않으면 이름은 명명된 매처의 이름에서 가져와요. 예를 들어 명명된 매처 @foo는 이 매처가 foo로 이름지어지게 해요. 이름을 지정하는 주된 이점은 같은 명명된 매처에서 둘 이상의 regexp 매처(예: path_regexp와 header_regexp)를 사용할 때예요.
캡처 그룹은 일치 후 플레이스홀더로 지시문에서 접근할 수 있어요:
{re.<name>.<capture_group>} 여기서:
-
<name>은 정규식의 이름이고, -
<capture_group>은 표현식의 캡처 그룹의 이름이나 번호예요.
이름 없는 {re.<capture_group>}도 편의를 위해 채워져요. 단, 여러 regexp 매처가 순차적으로 사용되면 플레이스홀더 값이 다음 매처에 의해 덮어써진다는 주의가 있어요.
캡처 그룹 0은 전체 regexp 일치, 1은 첫 번째 캡처 그룹, 2는 두 번째 캡처 그룹 등이에요. 그래서 {re.foo.1} 또는 {re.1} 모두 첫 번째 캡처 그룹의 값을 담아요.
이 매처는 자기 자신과 병합될 수 없으므로 명명된 매처당 path_regexp 패턴 하나만 있을 수 있어요. 더 필요하면 expression매처를 사용하는 것을 고려해보세요.
예제:
경로가 6자리 16진수 문자열 뒤에 파일 확장자로 .css 또는 .js가 오는 것으로 끝나고, {re.static.1}과 {re.static.2}(또는 각각 {re.1}과 {re.2})로 접근할 수 있는 캡처 그룹(( )로 둘러싸인 부분)이 있는 요청 일치:
@static path_regexp static \.([a-f0-9]{6})\.(css|js)$
명명된 매처에서 추론될 이름을 생략해 단순화할 수 있어요:
@static path_regexp \.([a-f0-9]{6})\.(css|js)$
CEL 표현식을 사용한 같은 것으로, file이 디스크에 존재하는지도 확인:
@static `path_regexp('\.([a-f0-9]{6})\.(css|js)$') && file()`
protocol
protocol http|https|grpc|http/<version>[+]
expression protocol('http|https|grpc|http/<version>[+]')
요청 프로토콜로. http, https, grpc 같은 넓은 프로토콜 이름을 사용하거나 http/1.1이나 http/2+ 같은 특정 또는 최소 HTTP 버전을 사용할 수 있어요.
명명된 매처당 protocol 매처 하나만 있을 수 있어요.
예제:
HTTP/2를 사용하는 요청 일치:
@http2 protocol http/2+
CEL 표현식 사용:
@http2 `protocol('http/2+')`
query
query <key>=<val>...
query ""
expression query({'<key>': '<val>'})
expression query({'<key>': ['<vals...>']})
쿼리 문자열 파라미터로. key=value 쌍의 시퀀스이거나 빈 문자열 ""이어야 해요. 키는 정확히 일치되고(대소문자 구분) 모든 값을 일치시키는 *도 지원해요. 값은 플레이스홀더를 사용할 수 있어요. 빈 문자열은 쿼리 파라미터가 없는 http 요청과 일치해요.
명명된 매처당 query 매처가 여러 개 있을 수 있고, 같은 키의 쌍은 OR로 결합돼요. 다른 키는 AND로 결합돼요. 그래서 매처의 모든 키가 적어도 하나의 일치하는 값을 가져야 해요.
잘못된 쿼리 문자열(나쁜 구문, 이스케이프되지 않은 세미콜론 등)은 파싱에 실패하므로 일치하지 않아요.
참고: 쿼리 문자열 파라미터는 단일 값이 아니라 배열이에요. 반복된 키가 쿼리 문자열에서 유효하고 각각 다른 값을 가질 수 있기 때문이에요. 이 매처는 구성된 값 중 하나라도 쿼리 문자열에 할당되면 키에 대해 일치해요. 쿼리 문자열을 사용하는 백엔드 애플리케이션은 쿼리 문자열 값이 배열이고 여러 값을 가질 수 있다는 점을 고려해야 해요.
예제:
모든 값을 가진 q 쿼리 파라미터 일치:
@search query q=*
값이 asc 또는 desc인 sort 쿼리 파라미터 일치:
@sorted query sort=asc sort=desc
CEL 표현식으로 q와 sort 모두 일치:
@search-sort `query({'sort': ['asc', 'desc'], 'q': '*'})`
remote_ip
remote_ip <ranges...>
expression remote_ip('<ranges...>')
리모트 IP 주소(즉 직접 피어의 IP 주소나 PROXY 프로토콜로 설정된 주소)로. 정확한 IP나 CIDR 범위를 받아요. IPv6 zone이 지원돼요.
지름길로 private_ranges를 사용해 모든 사설 IPv4 및 IPv6 범위를 일치시킬 수 있어요. 다음 모든 범위를 지정하는 것과 같아요: 192.168.0.0/16 172.16.0.0/12 10.0.0.0/8 127.0.0.1/8 fd00::/8 ::1
HTTP 헤더에서 파싱된 클라이언트의 "실제 IP"를 일치시키려면 대신 client_ip 매처를 사용하세요.
명명된 매처당 remote_ip 매처가 여러 개 있을 수 있고, 그 범위는 병합되어 OR로 결합돼요.
예제:
사설 IPv4 주소의 요청 일치:
@private-ipv4 remote_ip 192.168.0.0/16 172.16.0.0/12 10.0.0.0/8 127.0.0.1/8
이 매처는 일치를 반전시키기 위해 not 매처와 자주 짝을 이뤄요. 예를 들어 공개 IPv4 및 IPv6 주소(모든 사설 범위의 반대)의 모든 연결을 중단하려면:
example.com {
@denied not remote_ip private_ranges
abort @denied
respond "Hello, you must be from a private network!"
}
CEL 표현식에서는 이렇게 보여요:
@my-friends `remote_ip('12.23.34.45', '23.34.45.56')`
url_pattern
url_pattern <pattern> {
base_url <url>
ignore_case
}
expression url_pattern('<pattern>')
expression url_pattern('<pattern>', '<base_url>')
URL 패턴으로. 이는 웹 브라우저의 URLPatternAPI와 같은 구문을 사용해요. path 매처와 비교해 명명된 그룹(:id), 정규식으로 제한된 그룹(:id([0-9]+)), 선택적 부분({/*}?), 패턴 어디서든 와일드카드(*)를 지원해요.
****은 일치시킬 URL 패턴이에요. 상대 패턴(/로 시작, 예: /books/:id)은 어떤 스킴과 호스트에서든 요청 경로와 일치해요. 절대 패턴(예: https://example.com/books/:id)은 스킴과 호스트도 일치하며, 그룹을 포함할 수 있어요(예: https://:sub.example.com/*). 패턴에 쿼리 문자열 부분이 없으면 모든 쿼리 문자열이 허용돼요.
base_url은 주어진 URL을 기준으로 상대 패턴을 해석하며, 그 URL의 스킴과 호스트로 일치를 제한해요. 예를 들어 base URL이 https://example.com인 /books/:id는 패턴 https://example.com/books/:id와 같아요.
ignore_case는 일치를 대소문자 구분하지 않게 해요. path 매처와 달리 URL 패턴은 기본적으로 대소문자를 구분해요.
path 매처처럼 일치 전에 요청 경로는 URL 디코드되고 디렉터리 이동 점이 정리돼요. 패턴의 경로에도 여러 슬래시가 없으면 여러 슬래시가 병합돼요.
요청의 스킴은 연결이 TLS를 사용하면 https, 그렇지 않으면 http예요. 호스트는 있으면 Host 헤더의 포트를 포함하므로, 비표준 포트의 사이트에 대한 절대 패턴은 그 포트를 포함해야 해요(예: https://example.com:8443/*).
패턴의 그룹이 캡처한 값은 일치 후 플레이스홀더로 지시문에서 접근할 수 있어요:
-
{http.url_pattern.<component>.<group>}여기서: -
<component>는 그룹이 있는 URL의 부분이에요:protocol,hostname,port,pathname, 또는search(쿼리 문자열), -
<group>은 명명된 그룹의 이름이거나, URL의 그 부분 안에서0부터 세는 와일드카드*같은 이름 없는 그룹의 번호예요.
예를 들어 /books/:id/*가 /books/42/chapters/1과 일치한 후, 플레이스홀더 {http.url_pattern.pathname.id}는 42를 담고 {http.url_pattern.pathname.0}는 chapters/1을 담아요.
명명된 매처당 url_pattern 매처 하나만 있을 수 있어요. 더 필요하면 expression매처를 사용하는 것을 고려해보세요.
예제:
숫자 ID로 책을 요청하고, 응답에서 ID를 사용:
example.com {
@book url_pattern /books/:id([0-9]+)
respond @book "Book number {http.url_pattern.pathname.id}"
}
선택적 부분을 사용해 /docs와 그 아래 모든 것을 일치:
@docs url_pattern /docs{/*}?
example.com의 모든 서브도메인에 대한 HTTPS 요청 일치, 서브도메인을 {http.url_pattern.hostname.sub}에 캡처:
@subdomain url_pattern https://:sub.example.com/*
대소문자를 무시하며 특정 호스트에 대한 API 요청 일치:
@api url_pattern /api/:version/* {
base_url https://example.com
ignore_case
}
CEL 표현식으로 두 패턴 일치:
@content `url_pattern('/books/:id') || url_pattern('/authors/:name')`
vars
vars <variable> <values...>
expression vars({'<variable>': '<value>'})
expression vars({'<variable>': ['<values...>']})
요청 컨텍스트의 변수 값이나 플레이스홀더 값으로. 여러 값을 지정해 가능한 값 중 하나와 일치시킬 수 있어요(OR).
인수는 변수 이름이거나 중괄호 { }의 플레이스홀더일 수 있어요. (첫 번째 파라미터에서는 플레이스홀더가 확장되지 않아요.)
이 매처는 map지시문이 출력을 설정하고, 라우트 안의 vars지시문 또는 요청 컨텍스트에 어떤 정보를 설정하는 플러그인과 짝을 이룰 때 가장 유용해요.
예제:
map지시문의 magic_number라는 이름의 출력을 값 3 또는 5로 일치:
vars {magic_number} 3 5
임의의 플레이스홀더 값, 즉 인증된 사용자 ID가 Bob 또는 Alice인 것 일치:
vars {http.auth.user.id} Bob Alice
vars지시문으로 변수를 설정하고 vars매처로 그에 일치시키는 완전한 예제. 여기서 두 요청 헤더를 하나의 변수로 결합하고 그 변수에 일치시켜요:
example.com {
vars combined_header "{header.Foo}_{header.Bar}"
@special vars {vars.combined_header} "123_456"
handle @special {
respond "You sent Foo=123 and Bar=456!"
}
handle {
respond "Foo and Bar were not special."
}
}
CEL 표현식에서는 이렇게 보여요:
@magic `vars({'magic_number': ['3', '5']})`
vars_regexp
vars_regexp [<name>] <variable> <regexp>
expression vars_regexp('<name>', '<variable>', '<regexp>')
expression vars_regexp('<variable>', '<regexp>')
사용되는 정규식 언어는 Go에 포함된 RE2예요. RE2 구문 참조와 Go regexp 구문 개요를 참고하세요.
v2.8.0부터 name을 제공하지 않으면 이름은 명명된 매처의 이름에서 가져와요. 예를 들어 명명된 매처 @foo는 이 매처가 foo로 이름지어지게 해요. 이름을 지정하는 주된 이점은 같은 명명된 매처에서 둘 이상의 regexp 매처(예: vars_regexp와 header_regexp)를 사용할 때예요.
캡처 그룹은 일치 후 플레이스홀더로 지시문에서 접근할 수 있어요:
{re.<name>.<capture_group>} 여기서:
-
<name>은 정규식의 이름이고, -
<capture_group>은 표현식의 캡처 그룹의 이름이나 번호예요.
이름 없는 {re.<capture_group>}도 편의를 위해 채워져요. 단, 여러 regexp 매처가 순차적으로 사용되면 플레이스홀더 값이 다음 매처에 의해 덮어써진다는 주의가 있어요.
캡처 그룹 0은 전체 regexp 일치, 1은 첫 번째 캡처 그룹, 2는 두 번째 캡처 그룹 등이에요. 그래서 {re.foo.1} 또는 {re.1} 모두 첫 번째 캡처 그룹의 값을 담아요.
regexp 패턴은 병합될 수 없으므로 변수 이름당 정규식 하나만 지원돼요. 더 필요하면 expression매처를 사용하는 것을 고려해보세요. 여러 다른 변수에 대한 일치는 AND로 결합돼요.
예제:
map지시문의 magic_number라는 이름의 출력을 4로 시작하는 값으로 일치하고, {re.magic.1} 또는 {re.1}로 접근할 수 있는 캡처 그룹에 값을 캡처:
@magic vars_regexp magic {magic_number} ^(4.*)
명명된 매처에서 추론될 이름을 생략해 단순화할 수 있어요:
@magic vars_regexp {magic_number} ^(4.*)
CEL 표현식에서는 이렇게 보여요:
@magic `vars_regexp('magic_number', '^(4.*)')`