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

Вы просматриваете документацию 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. Добавьте условие в качестве элемента к сущности, к которой применяется условие. В этом примере условие является компонентом потока. Следовательно, поток будет выполняться всякий раз, когда условие оценивается как истинное.

<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 , то выполняется условный поток, и применяется политика преобразования XML в JSON под названием ConvertToJSON . В противном случае поток не выполняется, и XML-ответ возвращается запрашивающему приложению без изменений (в формате XML).

Пример 2

Рассмотрим конкретный пример, в котором вам нужно преобразовать ответное сообщение из XML в JSON — но только для мобильных устройств. Сначала создайте политику, которая будет преобразовывать ответ в формате XML от Weather API в 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 , в результате чего условное выражение оценивается как истинное, и выполняется условный поток 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-код демонстрирует условие шага. Политика 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 /

Выполняется ли политика? Да, в пути есть еще один элемент (часть после " /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-прокси, прокси также позволяют определять условные потоки, которые сопоставляются с ресурсами на вашем бэкэнде. По сути, "если поступает GET-запрос к ресурсу /reports, 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-запрос с URL-адресами /reports и /forecasts , 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 до /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 служб для разработчиков предоставляет метод для вывода списка всех приложений, принадлежащих разработчику. Путь 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 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 .

При желании этого можно добиться и без использования регулярных выражений следующим образом:

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

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

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

<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}».

Рассмотрим конкретный пример. Предположим, сервер аутентификации возвращает список ролей в виде строки, разделённой запятыми: "editor, author, guest".

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

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

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

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

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

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

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

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

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

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