Матчинг запросов
Матчи запросов могут использоваться для фильтрации (или классификации) запросов по различным критериям.
Синтаксис
В файле Caddy, непосредственно после директивы, может следовать токен матча, который ограничивает область действия директивы. Токен матча может иметь одну из этих форм:
-
*для соответствия всем запросам (шаблон; по умолчанию). -
/pathначинается с косой черты для соответствия пути запроса. -
@nameдля указания именованного матча.
Если директива поддерживает матчи, она будет отображаться как [<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
Матчинг по шаблонам
Матчинг по шаблону (или "захват всего") * соответствует всем запросам и необходим только в том случае, если токен матча обязателен. Например, если первый аргумент, который вы хотите передать в директиву, также является путем, он будет выглядеть точно как матчинг по пути! Таким образом, вы можете использовать матчинг по шаблону, чтобы избежать неоднозначности, например:
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`
Как и директивы, определения именованных матчей должны находиться внутри блоков сайта, которые их используют.
Определение именованного матча образует набор матчей. Матчи в наборе соединяются операцией И; т.е. все они должны соответствовать. Например, если в наборе есть и header, и path матчи, то оба должны соответствовать.
Несколько матчей одного типа могут быть объединены (например, несколько path матчей в одном наборе) с использованием булевой алгебры (И/ИЛИ), как описано в соответствующих разделах ниже.
Для более сложной логики булевого соответствия рекомендуется использовать expression матчинг для написания выражения CEL, которое поддерживает и &&, или ||, а также скобки ( ).
Стандартные матчи
Полная документация по матчам доступна в документации каждого модуля матча.
Запросы могут быть сопоставлены следующими способами:
client_ip
client_ip <ranges...>
expression client_ip('<ranges...>')
По адресу IP клиента. Принимает точные IP-адреса или диапазоны CIDR. Поддерживаются IPv6-зоны.
Этот матчинг лучше всего использовать при конфигурации глобального параметра trusted_proxies, в противном случае он ведет себя идентично remote_ip матчингу. Только запросы от доверенных прокси будут иметь свой IP-адрес клиента, проанализированный в начале запроса; для недоверенных запросов используется IP-адрес удаленного узла.
В качестве сокращения, 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 матчей на именованный матчинг, и их диапазоны будут объединены и соединены операцией ИЛИ.
Пример:
Сопоставление запросов с частных 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 <cel...>
Любое выражение CEL (Common Expression Language), возвращающее true или false.
Плейсхолдеры Caddy (или сокращения Caddyfile) могут использоваться в этих выражениях CEL, так как они предварительно обрабатываются и преобразуются в обычные вызовы функций CEL перед интерпретацией средой CEL.
Большинство других матчей запросов также могут использоваться в выражениях в качестве функций, что обеспечивает большую гибкость для логики булевых операций, чем вне выражений. См. документацию по каждому матчу для поддержки синтаксиса внутри выражений CEL.
Для удобства имя матча может быть опущено при определении именованного матча, состоящего только из выражения 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 {
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.Чтобы сопоставить каталоги, добавьте косному слэшу
/к пути. Все пути к файлам относительны к корню сайта корень, и шаблоны 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разделит путь по первому разделителю в списке, который встречается в каждом пути к файлу для проверки. Для каждого разделителя левая часть разделителя, включая сам разделитель, будет путём к файлу, который проверяется. Например,/remote.php/dav/с разделителем.phpпопытается найти файл/remote.php. Каждый разделитель должен появляться в конце компонента пути URI, чтобы использоваться в качестве разделителя. Это узкоспециализированная настройка, и она в основном используется при обслуживании PHP-сайтов.
Так как try_files с политикой first_exist очень часто используется, для этого существует сокращённая запись:
file <files...>
Пустой file-матчер (без файлов в списке) проверит, существует ли запрашиваемый файл — дословно из URI, относительно корня сайта корень сайта. Это фактически эквивалентно file {path}.
После сопоставления будут доступны четыре новых плейсхолдера:
-
{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, поэтому здесь используется конкатенация. Кроме того, необходимо использовать полную форму, если нужно конкатенировать с плейсхолдерами из-за текущих ограничений парсинга:
@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 не требуется).
- Если префикс
-
<value>— значение поля, которое должно совпадать для сопоставления. Можно указать одно или несколько значений.- Если префикс
*, выполняется быстрое соответствие по суффиксу (появление в конце). - Если суффикс
*, выполняется быстрое соответствие по префиксу (появление в начале). - Если заключено в
*, выполняется быстрое соответствие по подстроке (появление где-либо). - В противном случае выполняется быстрое точное соответствие.
- Если префикс
Разные поля заголовков в одном наборе соединены оператором И. Несколько значений одного поля соединены оператором ИЛИ.
Обратите внимание, что поля заголовков могут быть повторяющимися и иметь разные значения. Прикладные программы на стороне сервера ОБЯЗАНЫ учитывать, что значения полей заголовков — это массивы, а не отдельные значения, и Caddy не интерпретирует их смысл в подобных случаях.
Пример:
Сопоставление запросов с заголовком Connection содержащим Upgrade:
@upgrade header Connection *Upgrade*
Сопоставление запросов с заголовком Foo содержащим bar или baz:
@foo {
header Foo bar
header Foo baz
}
Сопоставление запросов, у которых вообще нет поля заголовка Foo:
@not_foo header !Foo
Используя выражение CEL, сопоставляем запросы WebSocket, проверяя заголовок 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>')
Как и header, но поддерживает регулярные выражения.
Используемый язык регулярных выражений — RE2, включенный в Go. См. справочник по синтаксису RE2 и обзор синтаксиса регулярных выражений в Go.
Начиная с версии 2.8.0, если name не указан, имя будет взято из имени именованного матчера. Например, именованный матчер @foo заставит этот матчер получить имя foo. Основное преимущество указания имени заключается в том, что если используется несколько матчеров regexp (например, header_regexp и path_regexp, или несколько различных полей заголовков) в одном именованном матчере.
К группам захвата можно получить доступ через плейсхолдеры в директивах после сопоставления:
-
{re.<name>.<capture_group>}, где:-
<name>— имя регулярного выражения, -
<capture_group>— имя или номер группы захвата в выражении.
-
-
{re.<capture_group>}без имени также заполняется для удобства. Оговорка заключается в том, что если последовательно используются несколько матчеров regexp, то значения плейсхолдеров будут перезаписаны следующей матчером.
Группа захвата 0 — это полное совпадение регулярного выражения, 1 — первая группа захвата, 2 — вторая группа захвата и т. д. Таким образом, {re.foo.1} или {re.1} оба содержат значение первой группы захвата.
Поддерживается только одно регулярное выражение на поле заголовка, поскольку шаблоны regexp не могут быть объединены; если вам нужно больше, рассмотрите использование expression матчера. Сопоставления с несколькими разными полями заголовков будут соединены оператором И.
Пример:
Сопоставление запросов, где заголовок Cookie содержит login_, за которым следует шестнадцатеричная строка, с группой захвата, к которой можно получить доступ с помощью {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 запроса.
Поскольку большинство блоков сайта уже указывают хосты в адресе сайта, этот матчер чаще используется в блоках сайта, использующих подстановку имени хоста (см. шаблон подстановочных символов в сертификатах), но где требуется логика, специфичная для имени хоста.
Несколько host-матчеров будут соединены оператором ИЛИ.
Пример:
Сопоставление одного поддомена:
@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. Можно сопоставить один или несколько методов.
Несколько method-матчеров будут соединены оператором ИЛИ.
Примеры:
Сопоставление запросов с методом GET:
@get method GET
Сопоставление запросов с методами PUT или DELETE:
@put-delete method PUT DELETE
Сопоставление только методов чтения с использованием выражения CEL:
@read `method('GET', 'HEAD', 'OPTIONS')`
not
not <matcher>
или, для отрицания нескольких матчеров, которые объединяются оператором И, откройте блок:
not {
<matchers...>
}
Результаты включённых матчеров будут инвертированы.
Примеры:
Сопоставление запросов с путями, которые НЕ начинаются с /css/ или /js/.
@not-assets {
not path /css/* /js/*
}
Сопоставление запросов, которые НЕ имеют:
- префикса пути
/api/, ИЛИ - метода запроса
POST
т. е. должны не иметь ни одного из этих условий для соответствия:
@with-neither {
not path /api/*
not method POST
}
Сопоставление запросов, которые НЕ имеют ОБОИХ:
- префикса пути
/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/*) - Только посередине, для совпадения по шару (
/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, потому что интервал, представленный %*, будет сравниваться без декодирования последовательностей экранирования.
Несколько путей будут объединены операцией ИЛИ.
Примеры:
Сопоставление нескольких каталогов и их содержимого:
@assets path /js/* /css/* /images/*
Сопоставление определенного файла:
@favicon path /favicon.ico
Сопоставление расширений файлов:
@extensions path *.js *.css
@assets `path('/js/*', '/css/*', '/images/*')`
path_regexp
path_regexp [<name>] <regexp>
expression path_regexp('<name>', '<regexp>')
expression path_regexp('<regexp>')
Как path, но поддерживает регулярные выражения. Выполняется по отношению к декодированному/неэкранированному пути URI.
Используемый язык регулярных выражений — RE2, включенный в Go. См. справочник по синтаксису RE2 и обзор синтаксиса регулярных выражений Go.
Начиная с версии 2.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-значным шестнадцатеричным числом, за которым следует .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, такие как http/1.1 или http/2+.
В именованном соответствии может быть только одно соответствие protocol.
Пример:
Сопоставление запросов, использующих HTTP/2:
@http2 protocol http/2+
@http2 `protocol('http/2+')`
query
query <key>=<val>...
expression query({'<key>': '<val>'})
expression query({'<key>': ['<vals...>']})
По параметрам строки запроса. Должен быть последовательностью пар key=value. Ключи сопоставляются точно (регистрозависимо), но также поддерживают * для соответствия любому значению. Значения могут использовать заполнители.
Может быть несколько соответствий query в одном именованном соответствии, а пары с одинаковыми ключами будут объединены операцией ИЛИ. Разные ключи будут объединены операцией И. Таким образом, все ключи в соответствии должны иметь по крайней мере одно соответствующее значение.
Неправильные строки запроса (неправильный синтаксис, неэкранированные точки с запятой и т. д.) не будут обработаны и, следовательно, не будут соответствовать.
ПРИМЕЧАНИЕ: Параметры строки запроса представляют собой массивы, а не отдельные значения. Это связано с тем, что повторяющиеся ключи допустимы в строках запроса, и каждый из них может иметь разное значение. Это соответствие будет соответствовать ключу, если любое из его настроенных значений назначено в строке запроса. Приложения на стороне сервера, использующие строки запроса, ДОЛЖНЫ учитывать, что значения строк запроса являются массивами и могут иметь несколько значений.
Пример:
Сопоставление параметра строки запроса q с любым значением:
@search query q=*
Сопоставление параметра строки запроса sort со значением asc или desc:
@sorted query sort=asc sort=desc
Сопоставление q и sort с помощью выражения CEL:
@search-sort `query({'sort': ['asc', 'desc'], 'q': '*'})`
remote_ip
remote_ip <ranges...>
expression remote_ip('<ranges...>')
По адресу удаленного IP-адреса (т. е. IP-адресу непосредственного peer). Принимает точные IP-адреса или диапазоны CIDR. Поддерживаются зоны IPv6.
В качестве сокращения можно использовать 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
Если вы хотите сопоставить «реальный IP» клиента, как он получен из заголовков HTTP, используйте соответствие client_ip вместо этого.
В именованном соответствии может быть несколько соответствий remote_ip, и их диапазоны будут объединены и объединены операцией ИЛИ.
Пример:
Сопоставление запросов с частных адресов 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')`
vars
vars <variable> <values...>
По значению переменной в контексте запроса или значению заполнителя. Для соответствия может быть указано несколько значений (объединение ИЛИ).
Аргумент <variable> может быть либо именем переменной, либо заполнителем в фигурных скобках { }. (Заполнители не расширяются в первом параметре.)
Это соответствие наиболее полезно при совместном использовании с map директивой, которая устанавливает выходы, или с плагинами, которые устанавливают какую-либо информацию в контексте запроса.
Пример:
Сопоставление вывода map директивы с именем magic_number для значений 3 или 5:
vars {magic_number} 3 5
Сопоставление произвольного значения заполнителя, т. е. идентификатора аутентифицированного пользователя, либо Bob, либо Alice:
vars {http.auth.user.id} Bob Alice
vars_regexp
vars_regexp [<name>] <variable> <regexp>
Как vars, но поддерживает регулярные выражения.
Используемый язык регулярных выражений — RE2, включенный в Go. См. справочник по синтаксису RE2 и обзор синтаксиса регулярных выражений Go.
Начиная с версии 2.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 соответствия. Соответствия с несколькими переменными будут объединены операцией И.
Пример:
Сопоставление вывода map директивы с именем magic_number для значения, начинающегося с 4, захватывая значение в группе захвата, к которой можно получить доступ с помощью {re.magic.1} или {re.1}:
@magic vars_regexp magic {magic_number} ^(4.*)
Это можно упростить, опуская имя, которое будет определено по имени сопоставителю:
@magic vars_regexp {magic_number} ^(4.*)
© 2015-2025 Matthew Holt and The Caddy Authors
Licensed under the Apache License 2.0.
Caddy is a registered trademark of Stack Holdings GmbH.
https://caddyserver.com/docs/caddyfile/matchers