Условия с переменными потока

Вы просматриваете документацию Apigee Edge .
Перейти к документации Apigee X.
info

Условные операторы — распространённая структура управления во всех языках программирования. Как и любой язык программирования, конфигурация API-прокси поддерживает условные операторы для потоков, политик, шагов и правил маршрутизации. Определяя условные операторы, вы задаёте динамическое поведение своего API. Это динамическое поведение позволяет, например, преобразовывать XML в JSON только для мобильных устройств или настраивать маршрутизацию на URL-адрес бэкенда на основе типа контента или HTTP-команды запроса.

В этой теме показано, как использовать условия для динамического применения функций управления API во время выполнения без написания кода.

Настройте условные операторы

Условное поведение реализуется в прокси-серверах API с помощью комбинации условий и переменных . Условный оператор создаётся с помощью элемента Condition. Ниже представлено пустое условие:

<Condition></Condition>

Чтобы создать условный оператор, добавьте условный оператор и переменную, чтобы создать следующую структуру:

<Condition>{variable.name}{operator}{"value"}</Condition>

Поддерживаемые условные операторы включают = (равно), != (не равно) и > (больше). Для удобства чтения условные операторы также можно записывать в виде текста: equals , notequals , greaterthan .

При работе с путями URI можно использовать операторы ~/ или MatchesPath . Также можно сопоставлять регулярные выражения JavaRegex с помощью оператора ~~.

Условия используются для определения условных потоков API-прокси к ресурсам бэкенд-API, описанных в разделе Создание условных потоков к ресурсам бэкенд-API . Полный список условий см. в разделе Справочник условий .

Переменные

Условия выполняют свою работу, оценивая значения переменных . Переменная — это свойство HTTP-транзакции, выполняемой API-прокси, или свойство самой конфигурации API-прокси. Каждый раз, когда API-прокси получает запрос от приложения, Apigee Edge заполняет длинный список переменных, связанных с такими вещами, как системное время, сетевая информация приложения, HTTP-заголовки сообщений, конфигурация API-прокси, выполнение политик и так далее. Это создает расширенный контекст, который можно использовать для настройки условных операторов.

Переменные всегда записываются с точкой. Например, HTTP-заголовки в сообщении запроса доступны как переменные с именем request.header.{header_name} . Таким образом, для оценки заголовка Content-type можно использовать переменную request.header.Content-type . Например, request.header.Content-type = "application/json" указывает, что тип содержимого запроса должен быть JSON.

Представьте, что вам нужно создать условный оператор, который будет применять политику только в том случае, если запрос представляет собой GET-запрос. Чтобы создать условие, которое оценивает HTTP-глагол запроса, создайте следующий условный оператор. Переменная в этом условии — request.verb . Значение переменной — GET . Оператор — = .

<Condition>request.verb = "GET"</Condition>
Вы также можете использовать:
<Condition>request.verb equals "GET"</Condition>

Edge использует такое выражение для оценки условий. Приведённый выше пример оценивается как «истина», если HTTP-команда, связанная с запросом, — GET. Если HTTP-команда, связанная с запросом, — POST, то выражение оценивается как «ложь».

Чтобы включить динамическое поведение, вы можете прикрепить условия к потокам, шагам и правилам маршрутизации.

Прикрепляя условие к потоку, вы создаёте «условный поток». Условные потоки выполняются только при выполнении условия. К условному потоку можно прикрепить любое количество политик. Условный поток позволяет создавать узкоспециализированные правила обработки запросов и ответов, соответствующие определённым критериям.

Например, чтобы создать поток, который выполняется только в том случае, если глаголом запроса является GET:

<Flows>
  <Flow name="ExecuteForGETs">
  <Condition>request.verb="GET"</Condition>
  </Flow>
</Flows>

Чтобы создать один поток для GET-запросов и другой для POST-запросов:

<Flows>
  <Flow name="ExecuteForGETs">
  <Condition>request.verb="GET"</Condition>
  </Flow>
  <Flow name="ExecuteForPOSTs">
  <Condition>request.verb="POST"</Condition>
  </Flow>
</Flows>

Как показано в примере ниже, вы можете применить это условие к самому шагу политики. Следующее условие приводит к применению политики VerifyApiKey только в том случае, если запрос представляет собой POST-запрос.

<PreFlow name="PreFlow">
    <Request>
        <Step>
            <Condition>request.verb equals "POST"</Condition>
            <Name>VerifyApiKey</Name>
        </Step>
    </Request>
</PreFlow>

После определения таких условных потоков вы можете прикрепить к ним политики, что позволит API-прокси применять один набор политик для запросов GET и другой набор политик для запросов POST.

Подробную справочную информацию можно найти в следующих ресурсах:

Пример 1

В следующем примере показан один условный поток с именем Convert-for-devices , настроенный в потоке ответов ProxyEndpoint. Добавьте Condition как элемент к сущности, к которой применяется условие. В этом примере условие является компонентом потока. Следовательно, поток будет выполняться всякий раз, когда выражение принимает значение true.

<Flows>
  <Flow name="Convert-for-devices">
  <Condition>(request.header.User-Agent = "Mozilla")</Condition>
    <Response>
      <Step><Name>ConvertToJSON</Name></Step>
    </Response>
  </Flow>
</Flows>

Для каждого запроса, полученного от приложения, Edge сохраняет значения всех HTTP-заголовков в виде переменных. Если запрос содержит HTTP-заголовок User-Agent , этот заголовок и его значение сохраняются в виде переменной request.header.User-Agent .

Учитывая указанную выше конфигурацию ProxyEndpoint, Edge проверяет значение переменной request.header.User-Agent , чтобы увидеть, выполняется ли условие.

Если условие истинно, то есть значение переменной request.header.User-Agent равно Mozilla , то выполняется условный поток (Flow) и применяется политика XMLtoJSON, называемая ConvertToJSON . В противном случае поток (Flow) не выполняется, и XML-ответ возвращается неизменённым (в формате XML) запрашивающему приложению.

Пример 2

Рассмотрим конкретный пример, в котором вам нужно преобразовать ответное сообщение из XML в JSON, но только для мобильных устройств. Сначала создайте политику, которая будет преобразовывать ответ от Weather API в формате XML в JSON:

<XMLToJSON name="ConvertToJSON">
  <Options>
  </Options>
  <OutputVariable>response</OutputVariable>
  <Source>response</Source>
</XMLToJSON>

Приведённая выше конфигурация политики указывает прокси-серверу API принять ответное сообщение, выполнить преобразование из XML в JSON с настройками по умолчанию, а затем записать результат в новое ответное сообщение. (Если вы преобразуете сообщение- запрос из XML в JSON, вы просто устанавливаете оба этих значения в request .)

Поскольку вы хотите преобразовать ответы из XML в JSON, вам необходимо настроить условный поток ответа для выполнения преобразования. Например, чтобы преобразовать все ответы из XML в JSON перед их возвратом в клиентское приложение, настройте следующий поток ответа ProxyEndpoint.

<Flows>
  <Flow name="Convert-for-devices">
    <Response>
      <Step><Name>ConvertToJSON</Name></Step>
    </Response>
  </Flow>
</Flows>

При вызове API с использованием стандартного запроса ответ форматируется в формате JSON.

Однако ваша цель — преобразовывать прогнозы погоды в JSON только в том случае, если запрашивающим клиентом является мобильное устройство . Чтобы реализовать такое динамическое поведение, необходимо добавить условный оператор в Flow.

Тестирование условного потока

В этом примере запроса заголовок HTTP User-Agent установлен на Mozilla , в результате чего условный оператор оценивается как true и выполняется условный поток Convert-for-devices .

$ curl -H "User-Agent:Mozilla" http://{org_name}-test.apigee.net/weather/forecastrss?w=12797282

или, для красивого вывода, где доступен Python:

$ curl -H "User-Agent:Mozilla" http://{org_name}-test.apigee.net/weather/forecastrss?w=12797282 | python -mjson.tool

Пример ответа:

. . .

"yweather_forecast": [
         {
              "code": "11",
              "date": "12 Dec 2012",
              "day": "Wed",
              "high": "55",
              "low": "36",
              "text": "Showers"
          },
          {
              "code": "32",
              "date": "13 Dec 2012",
              "day": "Thu",
              "high": "56",
              "low": "38",
              "text": "Sunny"
          }
      ]
  }

. . .

Запрос, отправленный без заголовка User-Agent или со значением, отличным от Mozilla , приведет к ответу в формате XML.

$ curl http://{org_name}-test.apigee.net/weather/forecastrss?w=12797282

Возвращается неизмененный XML-ответ.

Пример ответа:

<yweather:forecast day="Wed" date="12 Dec 2012" low="36" high="55" text="Showers" code="11" /> <yweather:forecast day="Thu" date="13 Dec 2012" low="38" high="56" text="Sunny" code="32" />

Сопоставление с образцом

В этом разделе описывается, как использовать сопоставление шаблонов с условиями в потоке Apigee.

Операторы

В этом разделе описывается, как использовать следующие операторы сопоставления с шаблонами в условных операторах:

Спички

Давайте сначала рассмотрим условный оператор «Matches» или «~». Эти два оператора идентичны — английская версия «Matches» считается более удобной для чтения.

Краткое описание: Оператор «Matches» предоставляет два варианта. Либо сопоставить строку буквально, либо использовать подстановочный знак «*». Как и ожидалось, подстановочный знак соответствует нулю или более символам. Давайте разберёмся, как это работает.

Следующий XML-код демонстрирует условие Step. Политика SomePolicy выполняется, когда условие истинно. В этом примере мы проверяем переменную proxy.pathsuffix — встроенную переменную Edge, которая хранит суффикс пути запроса. Обратите внимание, что вы можете проверить значение любой переменной потока, содержащей строку. Таким образом, в данном случае, если базовый путь входящего запроса — /animals , а запрос — /animals/cat , то суффикс пути — это строка « /cat ».

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix Matches "/cat")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

Вопрос: Какой суффикс пути прокси-сервера приведёт к выполнению SomePolicy? Есть только один вариант.

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/cat

Выполняется ли политика? Да, поскольку суффикс пути к прокси-серверу точно совпадает с " /cat ". Политика не выполнится, если суффикс — /bat , /dog , / или любой другой.

Теперь рассмотрим этот условный оператор, в котором мы используем подстановочный знак « * »:

<Condition>(proxy.pathsuffix Matches "/*at")</Condition>

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/cat

Выполняется ли политика? Да, поскольку подстановочный знак соответствует любому символу, а "/cat » — это совпадение.

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/bat

Выполняется ли политика? Да, поскольку подстановочный знак соответствует любому символу, "/bat" — это совпадение.

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/owl

Выполняется ли политика? Конечно, нет — хотя подстановочный знак соответствует букве « o », буквы « wl » не совпадают.

Теперь давайте переместим подстановочный знак в конец суффикса:

<Condition>(proxy.pathsuffix Matches "/cat*")</Condition>

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/cat

Выполняется ли политика? Да, поскольку подстановочный знак соответствует нулю или более любым символам.

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/bat

Выполняется ли политика? Нет, « /bat » не подходит.

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/cat123

Выполняется ли политика? Да, подстановочный знак соответствует нулю или более любым символам, поэтому « 123 » даёт совпадение.

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/cat/bird/mouse

Выполняется ли политика? Да, поскольку подстановочный знак соответствует нулю или более любым символам, поэтому " /bird/mouse " вернет совпадение. Обратите внимание, что подобное выражение может привести к проблемам, поскольку оно соответствует всему после литеральных символов!

Вопрос: Чувствителен ли оператор Matches к регистру?

Да. Предположим, у вас такое состояние:

<Condition>(proxy.pathsuffix Matches "/*At")</Condition>

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/cat

Выполняется ли политика? Нет, подстановочный знак соответствует любой букве (независимо от регистра), но строчная «a» не соответствует «A».

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/bAt

Политика выполняется? Да, всё соответствует.

Вопрос: Как экранировать символы с помощью оператора Matches?

Используйте символ процента «%» для экранирования зарезервированных символов. Например:

<Condition>(proxy.pathsuffix Matches "/c%*at")</Condition>

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/cat

Выполняется ли политика? Нет, оператор Matches ищет строку «c*at».

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/c*at

Вопрос: Выполняется ли политика?

Да, этот путь, хоть и немного необычный, совпадает.

JavaRegex

Как видите, оператор «Matches» отлично подходит для простых ситуаций. Но вы можете использовать другой оператор — «JavaRegex» или «~~». Это один и тот же оператор, за исключением того, что JavaRegex считается более читабельным. Он называется JavaRegex, потому что позволяет сопоставлять шаблоны с регулярными выражениями, и Edge следует тем же правилам, что и классы из пакета java.util.regex в языке Java. Принцип работы оператора JavaRegex сильно отличается от принципа работы оператора Matches, поэтому важно не путать их!

Краткое описание: Оператор «JavaRegex» позволяет использовать синтаксис регулярных выражений в условных операторах.

Следующий код демонстрирует условие Step. Политика SomePolicy выполняется, если условие истинно. В этом примере мы проверяем переменную proxy.pathsuffix — встроенную переменную Edge, которая хранит суффикс пути запроса. Если базовый путь входящего запроса — /animals , а запрос — /animals/cat , то суффикс пути — это строка « /cat ».

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix JavaRegex "/cat")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

Вопрос: Какой суффикс пути прокси-сервера приведёт к выполнению SomePolicy? Как и в случае с оператором Matches, в этом случае существует только один вариант.

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/cat

Выполняется ли политика? Да, поскольку суффикс пути к прокси-серверу точно совпадает с " /cat ". Политика не выполнится, если суффикс — /bat , /dog или что-то ещё.

Теперь создадим регулярное выражение с квантификатором «*». Этот квантификатор соответствует нулю или более предшествующим символам.

<Condition>(proxy.pathsuffix JavaRegex "/c*t")</Condition>

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/cat

Выполняется ли политика? Нет! Квантификатор «*» соответствует нулю или более предшествующим символам , то есть « c ».

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/ccccct

Выполняется ли политика? Да, поскольку подстановочный знак соответствует нулю или более предшествующим символам.

Затем мы используем квантификатор « ? », который соответствует предыдущему символу один раз или не соответствует вообще.

<Condition>(proxy.pathsuffix JavaRegex "/ca?t")</Condition>

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/cat

Выполняется ли политика? Да. Квантификатор « ? » соответствует нулю или одному вхождению предыдущего символа, то есть « a ».

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/ct

Выполняется ли политика? Да. Квантификатор « ? » соответствует одному или ни одному из предшествующих символов. В данном случае символ «a» отсутствует, поэтому условие выполняется.

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/caat

Выполняется ли политика? Нет. Квантификатор «?» соответствует одному из предшествующих символов, то есть « a ».

Далее мы используем стиль регулярного выражения « [abc] » или «группирующий». Он соответствует символам « a », « b » или « c ».

<Condition>(proxy.pathsuffix JavaRegex "/[cbr]at")</Condition>

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/cat

Выполняется ли политика? Да. Мы используем регулярные выражения, и выражение « [cbr] » соответствует символам «c», «b» ИЛИ «r». Эти вызовы также являются совпадениями:

GET http://artomatic-test.apigee.net/matchtest/bat

GET http://artomatic-test.apigee.net/matchtest/rat

Но это не совпадение:

GET http://artomatic-test.apigee.net/matchtest/mat

Вопрос: Чувствителен ли оператор JavaRegex к регистру?

Да. Предположим, у вас такое состояние:

<Condition>(proxy.pathsuffix JavaRegex "/ca?t")</Condition>

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/cat

Выполняется ли политика? Да, регулярное выражение соответствует нулю или одному предыдущему символу, то есть «a».

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/cAt

Вопрос: Выполняется ли политика?

Нет, потому что заглавная буква «А» не соответствует строчной «а».

MatchesPath

Оператор MatchesPath также можно задать как "~/". Он немного похож на операторы Matches (~) и JavaRegex (~~). Но MatchesPath — это совершенно другое.

Просто помните, что этот оператор рассматривает путь как последовательность частей. Поэтому, если путь выглядит как /animals/cats/wild , вы можете считать, что путь состоит из частей « /animals », « /cats » и « /wild ».

Оператор MatchesPath позволяет использовать два подстановочных знака: одинарную звёздочку (*) и двойную звёздочку (**). Одинарная звёздочка соответствует одному элементу пути. Двойная звёздочка соответствует одному или нескольким элементам пути.

Рассмотрим пример. В этом примере мы проверяем переменную proxy.pathsuffix — встроенную переменную Edge, которая хранит суффикс пути запроса. Обратите внимание, что вы можете проверить значение любой переменной потока, содержащей строку.

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix MatchesPath "/animals/*")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

Вопрос: Какой суффикс пути прокси приведет к выполнению SomePolicy?

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/animals

Вопрос: Выполняется ли политика?

Нет, поскольку условие требует еще одного элемента пути после « /animals », как указано в « /* ».

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/animals /

Выполняется ли политика? Да, в пути есть ещё один элемент path (часть после « /animals/ »), но он просто пустой.

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/animals/cats

Выполняется ли политика? Да, поскольку в пути явно есть элемент (" /cats "), который идёт после " /animals ".

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/animals/cats/wild

Вопрос: Выполняется ли политика?

Нет, поскольку одна звездочка соответствует только одному элементу пути, а в этом API после « /animals » имеется более одного элемента.

Теперь давайте используем двойную звездочку:

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix MatchesPath "/animals/**")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

Вопрос: Какой суффикс пути прокси приведет к выполнению SomePolicy?

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/animals

Выполняется ли политика? Нет, поскольку условие требует как минимум одного следующего элемента пути, заданного как « /** ».

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/animals /

Выполняется ли политика?

Да, у пути есть еще один элемент пути (часть после « /animals/ »), но он просто пустой.

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/animals/cats

Выполняется ли политика?

Да, потому что в пути есть как минимум один элемент, следующий после « /animals ».

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/animals/cats/wild

Выполняется ли политика?

Да, потому что путь содержит более одного элемента, следующего за « /animals ».

Смешивание звездочек

Для дальнейшего уточнения пути поиска можно использовать комбинации одинарной (*) и двойной (**) звездочки.

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix MatchesPath "/animals/*/wild/**")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

API-вызов:

Все эти вызовы API дадут совпадение:

GET http://artomatic-test.apigee.net/matchtest/animals/cats/wild/

и

GET http://artomatic-test.apigee.net/matchtest/animals/dogs/wild/austrailian

и

GET http://artomatic-test.apigee.net/matchtest/animals/birds/wild/american/finches

API-ресурсы

RESTful-сервисы представляют собой коллекции ресурсов API . Ресурс API — это фрагмент пути URI, идентифицирующий некую сущность, к которой разработчики могут получить доступ, вызвав ваш API. Например, если ваш сервис предоставляет сводки погоды и прогнозы погоды, ваш бэкенд-сервис может определить два ресурса API:

  • http://mygreatweatherforecast.com /reports
  • http://mygreatweatherforecast.com /forecasts

При создании API-прокси (как показано в разделе «Создание первого API-прокси ») вы как минимум создаёте базовый URL-адрес псевдонима, который соответствует вашей внутренней службе. Например:

Базовый URL-адрес бэкэнда Новый/эквивалентный URL-адрес прокси-сервера API
http://mygreatweatherforecast.com http://{your_org}-{environment}.apigee.net/mygreatweatherforecast

На этом этапе вы можете совершать API-вызовы к своему бэкенду, используя любой из базовых URL. Но когда вы используете URL-адрес прокси-API, всё становится интереснее.

Помимо аналитики API, которую Edge начинает собирать при использовании прокси-сервера API, прокси-серверы также позволяют определять условные потоки, которые сопоставляются с ресурсами на вашем бэкенде. По сути, «если к ресурсу /reports поступает вызов GET, Edge должен что-то сделать».

На следующем изображении показана разница в поведении двух URL-адресов, которые в конечном итоге обращаются к одному и тому же бэкенду. Один из них — URL-адрес ресурса без прокси-сервера, другой — прокси-сервер Edge API с условным потоком к тому же бэкенд-ресурсу. Мы подробнее опишем условные потоки ниже.

Как прокси-серверы API сопоставляются с определенными внутренними ресурсами

С помощью URL-адреса прокси-сервера API, сопоставленного с базовым URL-адресом внутренней службы (при создании прокси-сервера), вы можете добавлять условные потоки к определенным ресурсам, например ресурсам /reports и /forecasts упомянутым ранее.

Допустим, вам нужно, чтобы Edge «что-то делал» при поступлении вызовов к ресурсам /reports или /forecasts . На этом этапе вы не сообщаете Edge, что делать, а лишь указываете ему, что он должен прослушивать вызовы к этим ресурсам. Это делается с помощью условий. В вашем прокси-сервере API Edge вы можете создать условные потоки для /reports и /forecasts . Для наглядности следующий XML-код прокси-сервера API показывает, как могут выглядеть эти условия.

<Flows>
    <Flow name="reports">
        <Description/>
        <Request/>
        <Response/>
        <Condition>(proxy.pathsuffix MatchesPath "/reports") and (request.verb = "GET")</Condition>
    </Flow>
    <Flow name="forecasts">
        <Description/>
        <Request/>
        <Response/>
        <Condition>(proxy.pathsuffix MatchesPath "/forecasts") and (request.verb = "GET")</Condition>
    </Flow>
</Flows>

Эти условия гласят: «Когда поступает запрос GET с /reports и /forecasts в URL-адресе, Edge выполнит то, что вы (разработчик API) укажете, используя политики, которые вы прикрепляете к этим потокам.

Вот пример того, как Edge получает команду, что делать при выполнении условия. В следующем XML-коде API-прокси при отправке GET-запроса на https://yourorg-test.apigee.net/mygreatweatherforecast/reports Edge выполняет политику «XML-to-JSON-1» в ответе.

<Flows>
    <Flow name="reports">
        <Description/>
        <Request/>
        <Response>
            <Step>
                <Name>XML-to-JSON-1</Name>
            </Step>
        </Response>
        <Condition>(proxy.pathsuffix MatchesPath "/reports") and (request.verb = "GET")</Condition>
</Flow>

Помимо этих необязательных условных потоков, каждый API-прокси также имеет два потока по умолчанию: <PreFlow> , выполняемый перед условными потоками, и <PostFlow> , выполняемый после условных потоков. Они полезны для применения политик при любом вызове API-прокси. Например, если вы хотите проверять ключ API приложения при каждом вызове, независимо от того, к какому внутреннему ресурсу осуществляется доступ, вы можете добавить политику проверки ключа API к <PreFlow> . Подробнее о потоках см. в разделе «Настройка потоков» .

Создание условных потоков для внутренних ресурсов

Определение условных потоков к внутренним ресурсам в API-прокси совершенно необязательно. Однако эти условные потоки позволяют применять детальное управление и мониторинг.

Вы сможете:

  • Применяйте управление таким образом, чтобы оно отражало семантику вашей модели API.
  • Применять политики и сценарии поведения к отдельным путям ресурсов (URI)
  • Собирайте детальные метрики для аналитических служб

Например, представьте, что вам необходимо применить различные типы логики к ресурсам бэкэнда /developers to /apps.

Для этого вам нужно добавить два условных потока в ваш API-прокси: /developers и /apps .

В представлении «Разработка» на панели «Навигатор» редактора прокси-сервера API щелкните значок + рядом со значением по умолчанию в конечных точках прокси-сервера.

В окне «Новый условный поток» необходимо ввести следующие ключевые конфигурации:

  • Название потока : Разработчики
  • Тип состояния : Путь
  • Путь : /developers

Условие будет запущено (и политики будут выполнены), если вызов будет отправлен на прокси-сервер с /developers в конце URI.

Теперь добавьте условный поток для /apps и предположим, что вы хотите, чтобы условие срабатывало как для URI, так и для команды POST в запросе. Конфигурация включает в себя следующие настройки:

  • Название потока : Приложения
  • Тип условия : Путь и глагол
  • Путь : /apps
  • Глагол : POST

Условие будет запущено (и политики будут выполнены), если вызов будет отправлен на прокси-сервер с /apps в конце URI и командой POST.

На панели «Навигатор» вы увидите новые потоки для приложений и разработчиков .

Выберите один из потоков, чтобы просмотреть конфигурацию условного потока в представлении кода редактора прокси API:

<Flow name="Apps">
    <Description>Developer apps registered in Developer Services</Description>
    <Request/>
    <Response/>
    <Condition>(proxy.pathsuffix MatchesPath "/apps") and (request.verb = "POST")</Condition>
</Flow>

Как видите, ресурсы API — это просто условные потоки, которые оценивают путь URI входящего запроса. (Переменная proxy.pathsuffix идентифицирует URI запроса, который следует за BasePath, настроенным в конфигурации ProxyEndpoint.)

Каждый определяемый вами ресурс API реализуется условным потоком в прокси-сервере API. (См. Настройка потоков .)

После развертывания API-прокси в тестовой среде будет выполнен следующий запрос:

http://{org_name}-test.apigee.net/{proxy_path}/apps

приведет к тому, что условие будет оценено как истинное, и этот поток вместе со всеми связанными с ним политиками будет выполнен.

В следующем примере условия используется регулярное выражение Java для распознавания вызовов ресурса /apps с косой чертой в конце или без нее ( /apps или /apps/** ):

<Condition>(proxy.pathsuffix JavaRegex "/apps(/?)") and (request.verb = "POST")</Condition>

Более подробную информацию об этом типе условий см. в статье «Как сопоставлять независимо...» в сообществе Apigee .

Моделирование иерархических URI

В некоторых случаях вам понадобятся иерархические ресурсы API. Например, API Developer Services предоставляет метод для получения списка всех приложений, принадлежащих разработчику. Путь URI:

/developers/{developer_email}/apps

У вас могут быть ресурсы, в которых для каждой сущности в коллекции генерируется уникальный идентификатор, который иногда аннотируется следующим образом:

/genus/:id/species

Этот путь в равной степени применим к следующим двум URI:

/genus/18904/species
/genus/17908/species

Для представления этой структуры в ресурсе API можно использовать подстановочные знаки. Например:

/developers/*/apps
/developers/*example.com/apps
/genus/*/species

будет соответствующим образом разрешать эти иерархические URI как ресурсы API.

В некоторых случаях, особенно для API со сложной иерархией, может потребоваться разрешить всё ниже определённого фрагмента URI. Для этого используйте подстановочный знак в виде двух звёздочек в определении ресурса. Например, если вы определяете следующий ресурс API:
/developers/**

Этот ресурс API будет разрешать следующие пути URI:

/developers/{developer_email}/apps
/developers/{developer_email}/keys
/developers/{developer_email}/apps/{app_id}/keys

Вот как будет выглядеть условие условного потока в определении прокси API:

<Condition>(proxy.pathsuffix MatchesPath "/developers/**") and (request.verb = "POST")</Condition>

Больше примеров

Условие, прикрепленное к RouteRule

<RouteRule name="default">
 <!--this routing executes if the header indicates that this is an XML call. If true, the call is routed to the endpoint XMLTargetEndpoint-->
  <Condition>request.header.content-type = "text/xml"</Condition>
  <TargetEndpoint>XmlTargetEndpoint</TargetEndpoint>
</RouteRule>

Условие, прилагаемое к полису

<Step>
<!--the policy MaintenancePolicy only executes if the response status code is exactly 503-->
  <Condition>response.status.code = 503</Condition>
  <Name>MaintenancePolicy</Name>
</Step>

Условный поток

<!-- this entire flow is executed only if the request verb is a GET-->
<Flow name="GetRequests">
  <Condition>request.verb="GET"</Condition>
  <Request>
    <Step>
<!-- this policy only executes if request path includes a term like statues-->
<Condition>request.path ~ "/statuses/**"</Condition>
      <Name>StatusesRequestPolicy</Name>
    </Step>
  </Request>
  <Response>
    <Step>
<!-- this condition has multiple expressions. The policy executes if the response code status is exactly 503 or 400-->
<Condition>(response.status.code = 503) or (response.status.code = 400)</Condition>
      <Name>MaintenancePolicy</Name>
    </Step>
  </Response>
</Flow>

Примеры операторов в условиях

Вот несколько примеров операторов, используемых для создания условий:

  • request.header.content-type = "text/xml"
  • request.header.content-length < 4096 && request.verb = "PUT"
  • response.status.code = 404 || response.status.code = 500
  • request.uri MatchesPath "/*/statuses/**"
  • request.queryparam.q0 NotEquals 10

Практический пример: игнорировать «/» в конце пути.

Разработчики Edge обычно хотят обрабатывать оба суффикса пути: " /cat " и " /cat/ ". Это связано с тем, что некоторые пользователи или клиенты могут вызывать ваш API с дополнительным слешем в конце пути, и вам необходимо иметь возможность обрабатывать это в условных операторах. Именно этот вариант использования обсуждался в сообществе Apigee .

При желании вы можете добиться этого без использования Regex, вот так:

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>((proxy.pathsuffix = "/cat") OR (proxy.pathsuffix = "/cat/")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

Это хороший вариант. Он понятен и легко читается.

Однако то же самое можно сделать и с помощью Regex, вот так. Скобки используются для группировки части Regex в операторе, но они не обязательны.

<Condition>(proxy.pathsuffix JavaRegex "/cat(/?)"</Condition>

API-вызовы:

GET http://artomatic-test.apigee.net/matchtest/cat
or

GET http://artomatic-test.apigee.net/matchtest/cat /

Выполняется ли политика? Да. Обратите внимание, что в регулярном выражении символ « ? » означает: совпадение с нулём или одним из предшествующих символов. Следовательно, и « /cat », и « /cat/ » являются совпадениями.

API-вызов:

GET http://artomatic-test.apigee.net/matchtest/cat/spotted

Выполняется ли политика? Нет. Регулярное выражение соответствует нулю или только одному вхождению предыдущего символа, и ничего другого не допускается.

Сопоставление произвольных строк с помощью JavaRegex

Во всех примерах в этой теме мы показываем, как сопоставить одну из встроенных переменных потока: proxy.pathsuffix. Полезно знать, что сопоставление с шаблоном можно выполнять с любой произвольной строкой или переменной потока, независимо от того, является ли она встроенной переменной потока, например proxy.pathsuffix.

Например, если у вас есть условие, проверяющее произвольную строку, возможно, строку, возвращаемую в бэкенде, или строку, возвращаемую в результате поиска на сервере аутентификации, вы можете использовать операторы сопоставления для его проверки. При использовании JavaRegex регулярное выражение будет сравниваться со всей строкой субъекта. Если субъект — «abc», а регулярное выражение — «[az]», совпадения нет, поскольку «[az]» соответствует ровно одному буквенному символу. Выражение «[az]+» работает, как и «[az]*» и «[az]{3}».

Рассмотрим конкретный пример. Предположим, сервер аутентификации возвращает список ролей в виде строки, разделённой запятыми: «редактор, автор, гость».

Для проверки наличия роли редактора эта конструкция не подойдет, поскольку «редактор» — это только часть всей строки.

<Condition>returned_roles ~~ "editor"</Condition>

Однако эта конструкция будет работать:

<Condition>returned_roles ~~ ".*\beditor\b.*")</Condition>

Это работает, потому что учитывает переносы слов и любые другие части строки с префиксом и суффиксом .*.

В этом примере вы также можете проверить наличие слова «редактор» с помощью оператора Matches:

<Condition>returned_roles ~~ "*editor*")</Condition>

Однако в случаях, когда вам нужна большая точность, JavaRegex часто оказывается лучшим выбором.

Экранирование двойных кавычек в выражениях JavaRegex

Синтаксис Condition требует, чтобы выражение JavaRegex было заключено в двойные кавычки. Поэтому, если у вас есть выражение Regex, включающее двойные кавычки, вам нужен альтернативный способ их сопоставления. Решение — Unicode. Например, предположим, что вы передаёте заголовок, включающий двойные кавычки, например:
 -H 'content-type:multipart/related; type="application/xop+xml"'
Если вы попытаетесь сопоставить этот заголовок с условием Regex, вы получите ошибку Invalid Condition, поскольку выражение содержит двойные кавычки:
request.header.Content-Type ~~ "(multipart\/related)(; *type="application\/xop\+xml\")"
Решение заключается в замене двойных кавычек в кодировке ASCII их эквивалентом в кодировке Unicode, \u0022 . Например, следующее выражение корректно и даёт ожидаемый результат:
request.header.Content-Type ~~ "(multipart\/related)(; *type=\u0022application\/xop\+xml\u0022)"