Вы просматриваете документацию Apigee Edge .
Перейти к документации Apigee X. info
При обслуживании запросов от приложений API-прокси могут возникать различные ошибки. Например, API-прокси могут сталкиваться с сетевыми проблемами при взаимодействии с бэкэнд-сервисами, приложения могут предоставлять просроченные учётные данные, запросы могут быть неправильно отформатированы и так далее.
Когда при обращении клиентского приложения к прокси-API возникает ошибка, клиенту возвращается сообщение об ошибке. По умолчанию клиент получает зачастую зашифрованное сообщение об ошибке без подробностей или инструкций. Но если вы хотите заменить стандартные сообщения об ошибках более полезными пользовательскими сообщениями и даже дополнить их такими функциями, как дополнительные HTTP-заголовки, вам необходимо настроить собственную обработку ошибок в Edge.
Настраиваемая обработка ошибок также позволяет добавлять такие функции, как регистрация сообщений при возникновении ошибки.
Прежде чем говорить о реализации пользовательской обработки ошибок в ваших прокси-серверах API, полезно понять, как возникают ошибки и как прокси-серверы API на них реагируют.
Видео
Посмотрите следующие видеоролики, чтобы узнать больше об устранении неисправностей.
| Видео | Описание |
|---|---|
| Введение в обработку неисправностей и потоки ошибок | Узнайте об обработке ошибок и о том, что происходит при возникновении ошибки в прокси-сервере API. |
| Обрабатывайте неисправности, используя правила обработки неисправностей | Изучите, как обрабатывать неисправности, используя правила обработки неисправностей. |
| Вызов пользовательских ошибок с помощью политики RaiseFault | Вызывайте пользовательские ошибки во время выполнения API, используя политику RaiseFault. |
| Определить правила обработки сбоев в прокси-сервере API и целевых конечных точках | Определите правила обработки сбоев в прокси-сервере API и целевых конечных точках и поймите различия. |
| Понять порядок выполнения правил обнаружения неисправностей | Понимать порядок выполнения правил обработки сбоев в прокси-сервере API и целевых конечных точках. |
| Определить правило ошибки по умолчанию | Определите правило обработки ошибок по умолчанию для обработки общих ошибок в вашем API. |
Как возникают ошибки
Сначала мы просто рассмотрим, как возникают ошибки. Знание того, как возникают ошибки, поможет вам спланировать различные ситуации, в которых вам потребуется реализовать собственную обработку ошибок.
Автоматические ошибки
API-прокси автоматически выдает ошибку в следующих ситуациях:
- Политика выдаёт ошибку. Например, если вызов API отправляет просроченный ключ, политика VerifyAPIKey автоматически выдаёт ошибку; или если количество вызовов API превышает определённый лимит, политика квоты или политика SpikeArrest выдаёт ошибку. (См. справочник по ошибкам политик , чтобы узнать о типах ошибок, которые могут выдавать политики).
- Возникла проблема в потоке сообщений прокси-API, например, ошибка маршрутизации.
- Произошел сбой на внутреннем уровне, например ошибка HTTP из-за сбоев на уровне протокола, ошибок TLS/SSL или недоступности целевой службы.
- Произошел сбой на системном уровне, например, исключение нехватки памяти.
Более подробную информацию об этих ошибках можно найти в разделе «Таксономия ошибок» в этой теме.
Пользовательские ошибки
В ситуациях, когда автоматическая ошибка отсутствует, вы можете захотеть выдать пользовательскую ошибку, например, если ответ содержит слово «недоступно» или если код состояния HTTP больше 201. Для этого добавьте политику RaiseFault в соответствующее место в потоке прокси-сервера API.
Вы можете добавить политику RaiseFault в поток API-прокси так же, как и любую другую политику. В следующем примере конфигурации прокси-сервера политика Raise-Fault-1 прикрепляется к ответу TargetEndpoint. Если в ответе целевой службы присутствует слово «unavailable», политика RaiseFault выполняется и выдаёт ошибку.
<TargetEndpoint name="default">
...
<Response>
<Step>
<Name>Raise-Fault-1</Name>
<Condition>(message.content Like "*unavailable*")</Condition>
</Step>
</Response>Это просто для того, чтобы показать вам, что вы можете генерировать собственные ошибки. Более подробно о политике RaiseFault мы поговорим в разделе «Сравнение правил FaultRules и политики RaiseFault» .
Дополнительные примеры можно найти в этих сообщениях на форумах сообщества Apigee :
Что делают API-прокси при возникновении ошибок
Вот что происходит, когда прокси-сервер выдает ошибку.
Выйти из прокси-конвейера
Когда API-прокси сталкивается с ошибкой, независимо от причины её возникновения, он выходит из обычного конвейера , переходит в состояние ошибки и возвращает клиентскому приложению сообщение об ошибке. После перехода API-прокси в состояние ошибки он не может вернуться к обработке в обычном конвейере.
Например, предположим, что API-прокси имеет политики в следующем порядке в запросе ProxyEndpoint:
- Проверить ключ API
- Квота
- JSON в XML
Если при проверке ключа API возникает ошибка, прокси-сервер API переходит в состояние ошибки. Политики квоты и преобразования JSON в XML не выполняются, прокси-сервер не переходит к целевой конечной точке (TargetEndpoint), а клиентскому приложению возвращается сообщение об ошибке.
Проверить наличие неисправностей
В состоянии ошибки прокси-серверы API также проверяют наличие следующих элементов (по порядку) в конфигурации прокси-сервера API, прежде чем вернуть клиентскому приложению сообщение об ошибке по умолчанию:
- Раздел
<FaultRules>, содержащий логику для запуска пользовательских сообщений об ошибках (и других политик) на основе определенных вами условий. - Раздел
<DefaultFaultRule>, который вызывает сообщение об ошибке по умолчанию в следующих ситуациях:-
<FaultRules>не определены. - Ни один из существующих
<FaultRules>не будет выполнен. - Элемент
<AlwaysEnforce>имеет значение true.
-
По сути, API-прокси предоставляет вам возможность вернуть настраиваемое сообщение об ошибке и запустить другую логику. Если прокси не находит ни один из этих разделов или они существуют, но настраиваемая ошибка не была активирована, прокси отправляет собственное сообщение по умолчанию, сгенерированное Edge.
Простой пример обработки неисправностей
Начнём с простого примера: вызов API-прокси не содержит необходимого API-ключа. По умолчанию клиентскому приложению возвращается следующий ответ:
HTTP/1.1 401 Unauthorized Date: Wed, 20 Jul 2016 19:19:32 GMT Content-Type: application/json Content-Length: 150 Connection: keep-alive Server: Apigee Router * Connection #0 to host myorg-test.apigee.net left intact {"fault":{"faultstring":"Failed to resolve API Key variable request.queryparam.apikey","detail":{"errorcode":"steps.oauth.v2.FailedToResolveAPIKey"}}}
Пользователи вашего API могут понять сообщение об ошибке, а могут и нет. Кроме того, многие ошибки по умолчанию более тонкие и их сложнее расшифровать.
Как разработчик API, вы можете изменить это сообщение, чтобы оно соответствовало потребностям того, кто в конечном итоге получит сообщение об ошибке, будь то разработчик приложения iOS или внутренняя группа тестирования, у которой есть собственные требования к формату сообщений об ошибках.
Вот простой пример создания настраиваемого сообщения об ошибке для обработки этой ошибки. Для этого требуется 1) политика, определяющая настраиваемое сообщение, и 2) правило FaultRule, которое выполняет политику при возникновении ошибки на прокси-сервере.
1. Создайте политику, которая определяет пользовательское сообщение.
Сначала создайте политику, определяющую пользовательское сообщение об ошибке. Вы можете использовать любую политику, например, политику AssignMessage , которая может задавать полезную нагрузку и необязательные HTTP-заголовки, такие как код состояния и фраза-причина. Assign Message идеально подходит для этого. Она позволяет управлять полезной нагрузкой сообщения, задавать различные коды состояния HTTP, устанавливать различные фразы-причины HTTP и добавлять HTTP-заголовки.
Не прикрепляйте политику ни к одному потоку в прокси-сервере API. Достаточно, чтобы она просто существовала в пакете прокси-сервера. Для этого в редакторе прокси-сервера интерфейса управления перейдите на вкладку «Разработка» и на панели навигации нажмите значок «+» на панели «Политики».

Это позволяет создать политику, не прикрепляя её к потоку в прокси-сервере API. Политика, не прикреплённая ни к одному потоку, помечается значком «отсоединён» в списке политик, как показано рядом с политикой ключевого сообщения API на предыдущем рисунке.
Ниже приведен пример политики AssignMessage , которая:
- Возвращает сообщение JSON.
- Устанавливает код статуса HTTP (911, который, очевидно, не существует, просто для иллюстрации вашей гибкости). Код статуса отображается в заголовке HTTP.
- Задаёт HTTP-фразу-причину (для замены стандартной фразы-причины «Неавторизованный доступ» для этой ошибки отсутствия ключа API). Фраза-причина отображается рядом с кодом статуса в HTTP-заголовке.
- Создает и заполняет новый HTTP-заголовок с именем
invalidKey.
<AssignMessage async="false" continueOnError="false" enabled="true" name="invalid-key-message"> <DisplayName>Invalid key message</DisplayName> <Set> <Payload contentType="application/json">{"Citizen":"Where's your API key? I don't see it as a query parameter"}</Payload> <StatusCode>911</StatusCode> <ReasonPhrase>Rejected by API Key Emergency Services</ReasonPhrase> </Set> <Add> <Headers> <Header name="invalidKey">Invalid API key! Call the cops!</Header> </Headers> </Add> <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables> <AssignTo createNew="false" transport="http" type="request"/> </AssignMessage>
При выполнении этой политики ответ клиентскому приложению будет выглядеть следующим образом. Сравните его с ответом по умолчанию, показанным ранее.
HTTP/1.1 911 Rejected by API Key Emergency Services Date: Wed, 20 Jul 2016 18:42:36 GMT Content-Type: application/json Content-Length: 35 Connection: keep-alive invalidKey: Invalid API key! Call the cops! Server: Apigee Router * Connection #0 to host myorg-test.apigee.net left intact {"Citizen":"Where's your API key? I don't see it as a query parameter."}
Да, это немного глупо, но это показывает, чего можно добиться. По крайней мере, теперь разработчик, получающий сообщение, знает, что он забыл включить ключ API в качестве параметра запроса.
Но как эта политика реализуется? В следующем разделе мы расскажем, как это сделать.
2. Создайте <FaultRule>, который активирует политику.
В разделах <ProxyEndpoint> или <TargetEndpoint> конфигурации прокси-сервера добавьте XML-блок <FaultRules> , содержащий один или несколько отдельных разделов <FaultRule> . Каждое правило FaultRule представляет отдельную ошибку, которую нужно обработать. В этом простом примере мы будем использовать только одно правило FaultRule, чтобы показать, из чего оно состоит.
Вам также следует добавить <DefaultFaultRule> , чтобы предоставить общее сообщение об ошибке, если ни одно из ваших правил FaultRules не выполняется.
Пример
<ProxyEndpoint name="default">
...
<FaultRules>
<FaultRule name="invalid_key_rule">
<Step>
<Name>invalid-key-message</Name>
</Step>
<Condition>(fault.name = "FailedToResolveAPIKey")</Condition>
</FaultRule>
</FaultRules>
<DefaultFaultRule name="default-fault">
<Step>
<Name>Default-message</Name>
</Step>
</DefaultFaultRule>Ключевые моменты:
- Правила FaultRules определяются в ProxyEndpoint. Это важно. Подробнее о размещении правил FaultRules в ProxyEndpoint и TargetEndpoint мы поговорим позже.
-
<Name>— имя политики, которую нужно выполнить. Имя берётся из атрибутаnameполитики родительского элемента, как показано в примере политики ранее. <Condition>— Edge оценивает условие и выполняет политику только в том случае, если оно истинно. Если существует несколько правил FaultRule, которые оцениваются как истинные, Edge выполняет первое из них. ( Важно : порядок оценки правил FaultRule, сверху вниз или снизу вверх, различается для TargetEndpoint и ProxyEndpoint, как описано в разделе «Множественные правила FaultRule и логика выполнения» .) Если условие не указано, правило FaultRule автоматически считается истинным. Однако это не рекомендуется. Каждое правило FaultRule должно иметь своё собственное условие.<DefaultFaultRule>— если пользовательское правило FaultRule не выполняется, выполняется правило<DefaultFaultRule>, которое отправляет более общее пользовательское сообщение вместо скрытого сообщения по умолчанию, генерируемого Edge. Правило<DefaultFaultRule>также может содержать условие<Condition>, но в большинстве случаев его не нужно включать, поскольку оно должно быть выполнено в любом случае, в крайнем случае.Правило DefaultFaultRule обычно используется для возврата общего сообщения об ошибке в случае любой непредвиденной ошибки. Примером может служить сообщение с контактной информацией для службы технической поддержки. Этот ответ по умолчанию служит двум целям: предоставляет удобную для разработчика информацию и скрывает URL-адреса бэкенда или другую информацию, которая может быть использована для взлома системы.
Множественные правила ошибок и логика выполнения
В разделе «Простой пример обработки ошибок » мы использовали простой пример с одним правилом FaultRule и условием. В реальном проекте API, учитывая все возможные ошибки, скорее всего, будет несколько правил FaultRule и правило DefaultFaultRule как в <ProxyEndpoint> , так и в <TargetEndpoint> . Однако в конечном итоге, когда прокси-сервер API переходит в состояние ошибки, выполняется только одно правило FaultRule.
В этом разделе описывается логика, используемая Edge при обработке правил FaultRules, от того, как он получает единственное правило FaultRule для выполнения, до того, как обрабатываются «внутренние» условия Step при срабатывании соответствующего правила FaultRule. В этом разделе также даются рекомендации по определению правил FaultRules в <ProxyEndpoint> , а не в <TargetEndpoint> , а также описывается связь между правилами FaultRules и политикой RaiseFault .
Выполнение FaultRules
Вкратце, вот логика, которую Edge использует при переходе прокси-сервера API в состояние ошибки. Обратите внимание, что существует небольшая разница между оценкой FaultRules в ProxyEndpoint и TargetEndpoint.
- Edge оценивает FaultRules либо в ProxyEndpoint, либо в TargetEndpoint, в зависимости от того, где произошла ошибка:
- ProxyEndpoint - Edge начинается с нижнего
<FaultRule>в XML-конфигурации и продвигается вверх, оценивая<Condition>каждого<FaultRule>(«внешнее» условие, а не «внутренние» условия<Step>). - TargetEndpoint - Edge начинается с верхнего
<FaultRule>в XML-конфигурации и продвигается вниз, оценивая<Condition>каждого<FaultRule>(«внешнее» условие, а не «внутренние» условия<Step>).
- ProxyEndpoint - Edge начинается с нижнего
- Выполняет первое правило FaultRule, условие которого истинно. Если у правила FaultRule нет условия, оно по умолчанию истинно.
- При выполнении правила FaultRule все шаги внутри него оцениваются по порядку, сверху вниз, в соответствии с XML-конфигурацией. Шаги без условий выполняются автоматически (применяются политики), а шаги с условием
<Condition>, которое оценивается как «истина», выполняются (условия, которые оцениваются как «ложь», не выполняются). Если правило FaultRule выполняется, но ни один шаг в нём не выполняется (поскольку их условия оцениваются как «ложь»), клиентскому приложению возвращается сообщение об ошибке по умолчанию, сгенерированное Edge. Правило
<DefaultFaultRule>не выполняется, поскольку Edge уже выполнил своё единственное правило FaultRule.
- При выполнении правила FaultRule все шаги внутри него оцениваются по порядку, сверху вниз, в соответствии с XML-конфигурацией. Шаги без условий выполняются автоматически (применяются политики), а шаги с условием
- Если правило FaultRule не выполняется, Edge выполняет правило
<DefaultFaultRule>, если оно присутствует.
Ниже приведены примеры со встроенными комментариями.
Выполнение ProxyEndpoint
Оценка правил ProxyEndpoint FaultRules выполняется снизу вверх, поэтому начните с последнего правила FaultRule в следующем примере и продвигайтесь вверх. Последним обратите внимание на правило DefaultFaultRule.
<ProxyEndpoint name="default">
...
<FaultRules>
<!-- 3. This FaultRule is automatically TRUE, because there's no "outer"
condition. But because the FaultRule just below this got
executed (bottom-to-top evaluation in a ProxyEndpoint), Edge
doesn't even evaluate this FaultRule.
Note that it's not a best practice to have a FaultRule without
an outer condition, which automatically makes the FaultRule true. -->
<FaultRule name="random-error-message">
<Step>
<Name>Random-fault</Name>
</Step>
</FaultRule>
<!-- 2. Let's say this fault is TRUE. The Quota policy threw a QuotaViolation
error. This is the first FaultRule to be TRUE, so it's executed.
Now the Steps are evaluated, and for the ones whose conditions
evaluate to TRUE, their policies are executed. Steps without
conditions are automatically true. -->
<FaultRule name="over_quota">
<Step>
<Name>developer-over-quota-fault</Name>
<Condition>(ratelimit.developer-quota-policy.exceed.count GreaterThan "0")</Condition>
</Step>
<Step>
<Name>global-over-quota-fault</Name>
<Condition>(ratelimit.global-quota-policy.exceed.count GreaterThan "0")</Condition>
</Step>
<Step>
<Name>log-error-message</Name>
</Step>
<Condition>(fault.name = "QuotaViolation")</Condition>
</FaultRule>
<!-- 1. Because this is the ProxyEndpoint, Edge looks at this FaultRule
first. But let's say this FaultRule is FALSE. A policy did not
throw a FailedToResolveAPIKey error. Edge moves UP to check
the next FaultRule. -->
<FaultRule name="invalid_key_rule">
<Step>
<Name>invalid-key-message</Name>
</Step>
<Condition>(fault.name = "FailedToResolveAPIKey")</Condition>
</FaultRule>
</FaultRules>
<!-- If no <FaultRule> is executed, the <DefaultFaultRule> is executed.
If a FaultRule is executed, but none of its Steps are executed,
The DefaultFaultRule is not executed (because Edge has already
executed its one FaultRule). -->
<DefaultFaultRule name="default-fault">
<Step>
<Name>Default-message</Name>
</Step>
</DefaultFaultRule>Выполнение TargetEndpoint
Оценка TargetEndpoint FaultRules выполняется сверху вниз, поэтому начните с первого FaultRule в следующем примере и двигайтесь вниз. В последнюю очередь обратите внимание на DefaultFaultRule.
<TargetEndpoint name="default">
...
<FaultRules>
<!-- 1. Because this is the TargetEndpoint, Edge looks at this FaultRule
first. Let's say this FaultRule is FALSE.
A policy did not throw a FailedToResolveAPIKey error.
Edge moves down to the next FaultRule. -->
<FaultRule name="invalid_key_rule">
<Step>
<Name>invalid-key-message</Name>
</Step>
<Condition>(fault.name = "FailedToResolveAPIKey")</Condition>
</FaultRule>
<!-- 2. Let's say this fault is TRUE. The Quota policy threw a QuotaViolation
error. This is the first FaultRule to be TRUE, so it's executed.
Now the Steps are evaluated, and for the ones whose conditions
evaluate to TRUE, their policies are executed. Steps without
conditions are automatically true. -->
<FaultRule name="over_quota">
<Step>
<Name>developer-over-quota-fault</Name>
<Condition>(ratelimit.developer-quota-policy.exceed.count GreaterThan "0")</Condition>
</Step>
<Step>
<Name>global-over-quota-fault</Name>
<Condition>(ratelimit.global-quota-policy.exceed.count GreaterThan "0")</Condition>
</Step>
<Step>
<Name>log-error-message</Name>
</Step>
<Condition>(fault.name = "QuotaViolation")</Condition>
</FaultRule>
<!-- 3. This FaultRule is automatically TRUE, because there's no "outer"
condition. But because the FaultRule just above this got
executed (top-to-bottom evaluation in a TargetEndpoint), Edge
doesn't even evaluate this FaultRule.
Note that it's not a best practice to have a FaultRule without
an outer condition, which automatically makes the FaultRule true. -->
<FaultRule name="random-error-message">
<Step>
<Name>Random-fault</Name>
</Step>
</FaultRule>
</FaultRules>
<!-- If no <FaultRule> is executed, the <DefaultFaultRule> is executed.
If a FaultRule is executed, but none of its Steps are executed,
The DefaultFaultRule is not executed (because Edge has already
executed its one FaultRule). -->
<DefaultFaultRule name="default-fault">
<Step>
<Name>Default-message</Name>
</Step>
</DefaultFaultRule>Порядок правил неисправности
Как видно из предыдущего примера, порядок, в котором вы размещаете FaultRules, важен и зависит от того, произошла ли ошибка в ProxyEndpoint или в TargetEndpoint.
Например:
| Заказ ProxyEndpoint | заказ TargetEndpoint |
|---|---|
В следующем примере, поскольку оценка производится снизу вверх, выполняется FaultRule 3, что означает, что FaultRule 2 и 1 не оцениваются. 5. Правило ошибки 1: ЛОЖЬ 4. Правило ошибки 2: ИСТИНА 3. Правило ошибки 3: ИСТИНА 2. Правило ошибки 4: ЛОЖЬ 1. Правило ошибки: 5 ЛОЖЬ | В следующем примере, поскольку оценка идет сверху вниз, выполняется FaultRule 2, что означает, что FaultRule 3, 4 и 5 не оцениваются. 1. Правило ошибки 1: ЛОЖЬ 2. Правило ошибки 2: ИСТИНА 3. Правило ошибки 3: ИСТИНА 4. Правило ошибки 4: ЛОЖЬ 5. Правило ошибки: 5 ЛОЖЬ |
Политики, которые следует включить
Вы можете выполнить любые политики из FaultRule, поместив их в Steps. Например, можно применить политику AssignMessage для форматирования ответа клиентскому приложению, а затем записать сообщение в журнал с помощью политики MessageLogging . Политики выполняются в том порядке, в котором вы их указали (сверху вниз в XML).
Правила сбоя срабатывают ТОЛЬКО в состоянии ошибки (о continueOnError)
Может показаться, что заголовок повторяется, но есть один конкретный нюанс, о котором следует знать, касающийся ошибки прокси-сервера, приводящей к переходу прокси-сервера API в состояние ошибки (или, скорее, к отказу от перехода в состояние ошибки): атрибут continueOnError в политике.
Подводя итог: API-прокси оценивает <FaultRules> и <DefaultFaultRule> только в том случае, если прокси-сервер перешёл в состояние ошибки. Это означает, что даже если условие FaultRule оценивается как истинное, оно не сработает, если прокси-сервер не находится в состоянии ошибки.
Однако вот пример возникновения ошибки, при котором прокси-сервер не переходит в состояние ошибки. В любой политике вы можете задать атрибут continueOnError для родительского элемента. Этот атрибут очень важен для обработки сбоев, поскольку он определяет, переходит ли прокси-сервер в состояние ошибки в случае сбоя политики. В большинстве случаев вам следует сохранить значение по умолчанию continueOnError="false" , которое переводит прокси-сервер в состояние ошибки в случае сбоя политики, и будет запущена ваша собственная обработка ошибок. Однако, если continueOnError="true" (например, если вы не хотите, чтобы сбой вызова службы останавливал выполнение прокси-сервера), прокси-сервер не перейдет в состояние ошибки при сбое этой политики и не будет проверять ваши правила FaultRules.
Информацию об ошибках регистрации при continueOnError="true" см. в разделе Обработка ошибок политики в текущем потоке .
Где определить FaultRules: ProxyEndpoint или TargetEndpoint
Когда в API-прокси возникает ошибка, она возникает либо в <ProxyEndpoint> (запрос клиентского приложения или ответ), либо в <TargetEndpoint> (запрос целевой службы или ответ). Edge ищет FaultRules в месте возникновения ошибки.
Например, если целевой сервер недоступен (код состояния HTTP 503), прокси-сервер API перейдёт в состояние ошибки в ответе <TargetEndpoint> , и обычный поток запросов через прокси-сервер API не будет продолжен до <ProxyEndpoint> . Если правила FaultRules определены только в <ProxyEndpoint> , они не будут обрабатывать эту ошибку.
Вот ещё один пример. Если политика RaiseFault в ответе <ProxyEndpoint> вызывает ошибку, правило FaultRule в <TargetEndpoint> не будет выполнено.
FaultRules против политики RaiseFault
Правила обработки ошибок и политика RaiseFault на первый взгляд могут показаться альтернативными способами обработки ошибок, и в каком-то смысле это действительно так. Но они также работают вместе. В этом разделе объясняется взаимосвязь между ними. Понимание этой взаимосвязи поможет вам разработать систему обработки ошибок, особенно если вы хотите использовать обе.
Вкратце:
- Правила обработки ошибок всегда оцениваются, когда прокси-сервер API переходит в состояние ошибки.
Политика RaiseFault — это способ перевести API-прокси в состояние ошибки, когда в противном случае ошибка не возникла бы.
Например, если вы хотите выдать ошибку, если код статуса HTTP в ответе целевой службы превышает 200, добавьте политику RaiseFault в поток ответа. Это будет выглядеть примерно так:
<TargetEndpoint name="default"> <PreFlow name="PreFlow"> ... <Response> <Step> <Name>Raise-Fault-1</Name> <!-- If the condition is true, the Raise-Fault-1 policy gets executed --> <Condition>(response.status.code GreaterThan "200")</Condition> </Step> </Response>Политика RaiseFault также отправляет сообщение об ошибке клиентскому приложению.
Что происходит, когда политика RaiseFault вызывает ошибку, которая переводит прокси-сервер в состояние ошибки, что потенциально приводит к выполнению правила FaultRule? Вот тут-то и возникают некоторые сложности. Если политика RaiseFault возвращает сообщение об ошибке , а правило FaultRule срабатывает и возвращает сообщение об ошибке, что возвращается клиентскому приложению?
- Поскольку FaultRule или DefaultFaultRule выполняются после политики RaiseFault, данные ответа FaultRule имеют приоритет.
- Данные ответа политики RaiseFault (код состояния, фраза причины или полезная нагрузка сообщения) используются, если эти данные не установлены FaultRule или DefaultFaultRule.
- Если и политика RaiseFault, и правило FaultRule добавляют пользовательские HTTP-заголовки, оба они включаются в ответ. Дублирующиеся имена заголовков создают заголовок с несколькими значениями.
Вот пример того, что задаёт политика RaiseFault и FaultRule, и что возвращается клиентскому приложению. Примеры приведены для краткости, а не для ознакомления с передовой практикой.
| ||
Клиентское приложение получает : Status Code: 468 Reason Phrase: Something happened Payload: {"Whoa":"Sorry."} Header: errorNote: woops,gremlins | <- Политика правил ошибок устанавливает следующее : Status Code: [none] Reason Phrase: Something happened Payload: {"Whoa":"Sorry."} Header: errorNote: gremlins | <- Политика RaiseFault устанавливает следующее :
Status Code: 468
Reason Phrase: Can't do that
Payload: {"DOH!":"Try again."}
Header:
errorNote: woops
|
Условия строительства
Условия — ключ к выполнению FaultRule. Условия FaultRule создаются так же, как и другие условия в Edge, например, для условных потоков или условий RaiseFault.
Чтобы поместить остальную часть этого раздела в контекст, вот пример правила ошибки, которое имеет внешнее условие FaultRule и внутреннее условие Step.
<FaultRule name="invalid_key_rule">
<Step>
<Name>invalid-key-message</Name>
<Condition>(oauthV2.Verify-API-Key-1.failed = true)</Condition>
</Step>
<Condition>(fault.name = "FailedToResolveAPIKey")</Condition>
</FaultRule>Переменные, специфичные для ошибок политики
Переменные fault.name и {policy_namespace}.{policy_name}.failed доступны, когда политика выдает ошибку.
fault.name
В случае сбоя политики перехватите ошибку в условии, используя переменную fault.name . Например:
<Condition>(fault.name = "policy_error_name")</Condition>
Имя ошибки отображается в сообщении об ошибке по умолчанию. Например, в следующем примере имя ошибки — FailedToResolveAPIKey . В этом случае переменной потока с именем fault.name присваивается значение FailedToResolveAPIKey .
{"fault":{"faultstring":"Failed to resolve API Key variable request.queryparam.apikey","detail":{"errorcode":"steps.oauth.v2.FailedToResolveAPIKey"}}}
Итак, условие будет выглядеть так:
<Condition>(fault.name = "FailedToResolveAPIKey")</Condition>
Список ошибок политики см. в справочнике ошибок политики.
{policy_namespace}.{policy_name}.failed
Переменная *.failed доступна при сбое политики. Ниже приведены примеры переменных *.failed для различных политик. Пространства имён политик см. в описании переменных потока в соответствующих разделах справочника по политикам .
- Политика RaiseFault :
raisefault.failed(одинаковая для всех политик RaiseFault) - Политика VerifyAPIKey :
oauthV2.{policy_name}.failed, например,oauthV2.Verify-API-Key-1.failed - Политика квот и политика SpikeArrest :
ratelimit.{policy_name}.failed, например,ratelimit.Quota-1.failed
Другие доступные переменные
Когда прокси-сервер API переходит в состояние ошибки, единственными доступными переменными для использования в условиях являются:
- Переменные политики, которые дали сбой.
- Переменные HTTP-сообщения, существующие в момент сбоя. Например, если в ответе возникает ошибка, правило FaultRule в
<TargetEndpoint>может использовать HTTP-данныеresponse.status.code,message.content,error.contentи т. д. В случае сбоя политики квот можно использовать переменнуюratelimit.{quota_policy_name}.exceed.count. Используйте инструмент Trace и справочные разделы по политикам , чтобы определить, какие переменные и HTTP-данные доступны.
Дополнительная информация
Условия : ссылка на условия , переменные и условия потока
- Ошибки : ссылка на ошибку политики
- Переменные : Справочник переменных и отдельные страницы справки политик для переменных, которые доступны в каждой политике.
Лучшие практики по устранению неисправностей
Обработка ошибок — важная задача архитектурного проектирования при разработке API-прокси. Важно уделить время тому, чтобы продумать, как и когда вы будете обрабатывать ошибки, определить содержание сообщений об ошибках и разработать форматы сообщений об ошибках. После того, как вы разберётесь с этим, используйте эти рекомендации для реализации обработки ошибок.
Ниже приведены некоторые передовые методы проектирования и создания систем обработки неисправностей:
- Для каждого правила FaultRule укажите «внешнее» условие
<Condition>(родственное элементу<Step>). Правила ошибок без внешнего условия автоматически оцениваются как «истина». «Внутренние» условия шага не используются для определения истинности или ложности правила FaultRule. Условия шага оцениваются только после того, как Edge выполнит содержащее их правило FaultRule. В правиле FaultRule обычно присутствует несколько шагов с политиками назначения сообщения (Assign Message) (или другими), каждая из которых имеет условие шага. Для обработки ошибок в нескольких политиках одного типа (например, в нескольких политиках квот) создайте по одному правилу FaultRule для каждой ошибки политики, которую вы, скорее всего, получите. Например, создайте правило FaultRule для каждой вероятной ошибки в политиках квот, такой как
QuotaViolation,InvalidMessageWeight,StartTimeNotSupported. (См. справочник по ошибкам политик. По мере обнаружения дополнительных ошибок, требующих обработки, вы можете вернуться к ним позже и добавить их в свои правила FaultRules. Итеративный подход допустим, хотя он требует повторного развертывания прокси-сервера.) Такой подход позволяет перехватывать ошибки одного и того же типа независимо от того, какая политика их вызывает, что повышает эффективность XML-файла FaultRules.Затем используйте внутренние условия Step, если вам требуется более точный контроль ошибок. Например, если вы применяете как индивидуальную квоту разработчика, так и глобальную квоту с двумя политиками в потоке запросов, настройте «внешнее» условие FaultRule так, чтобы оно срабатывало при ошибке
QuotaViolation(которая возникает при превышении квоты в любом случае). Затем настройте условия Step для оценки переменныхexceed.countв обеих политиках квот. Клиенту отправляется только соответствующая ошибка (превышение квоты разработчика или глобальной квоты). Вот пример такой конфигурации:<FaultRule name="over_quota"> <!-- This condition catches a QuotaViolation in *any* Quota policy --> <Condition>(fault.name = "QuotaViolation")</Condition> <Step> <Name>developer-over-quota-fault</Name> <Condition>(ratelimit.developer-quota-policy.exceed.count GreaterThan "0")</Condition> </Step> <Step> <Name>global-over-quota-fault</Name> <Condition>(ratelimit.global-quota-policy.exceed.count GreaterThan "0")</Condition> </Step> </FaultRule>Другой пример см. в этой ветке сообщества Apigee .
Для обработки ошибок при использовании одной политики одного типа рассмотрите одно правило обработки ошибок, которое будет выполняться при сбое этой политики, и включите несколько шагов, соответствующих каждой возможной ошибке. Это обеспечит эффективность XML за счет использования одного правила FaultRule вместо нескольких (по одному для каждого типа ошибки). Например:
<FaultRule name="raise-fault-3"> <!-- This condition catches *any* error in the Verify-API-Key-1 policy. --> <Condition>(oauthV2.Verify-API-Key-1.failed = "true")</Condition> <!-- This first step always executes, which handles errors you haven't mapped with inner conditions. --> <Step> <Name>Generic-Key-Fault</Name> </Step> <Step> <Name>Assign-Message-Raise-Fault-1</Name> <Condition>(fault.name = "FailedToResolveAPIKey")</Condition> </Step> <Step> <Name>Assign-Message-Raise-Fault-2</Name> <Condition>(fault.name = "InvalidApiKey")</Condition> </Step> </FaultRule>- Добавьте правила FaultRules, где будут возникать ошибки (клиентская сторона
<ProxyEndpoint>или целевая сторона<TargetEndpoint>). Включите правила FaultRules для каждой политики, которая появляется в каждом месте. - В FaultRules можно применить любую политику, которая может возвращать сообщение клиентскому приложению. Политика AssignMessage идеально подходит для этого. Также рассмотрите возможность регистрации сообщения с помощью политики MessageLogging, если вы хотите отслеживать ошибки.
- При использовании политик RaiseFault совместно с FaultRules координируйте данные ответа, отправляемые при возврате данных как политикой RaiseFault, так и FaultRule. Например, если политика RaiseFault сбрасывает код состояния HTTP, не сбрасывайте этот код в FaultRule. Худшее, что может произойти, — клиентскому приложению будет возвращен код состояния по умолчанию.
- Выполнение
<DefaultFaultRule>:- Если вы хотите, чтобы правило
<DefaultFaultRule>всегда выполнялось, когда не выполняется ни одно другое правило FaultRule, не включайте в него<Condition>. - Если вы хотите, чтобы
<DefaultFaultRule>всегда выполнялось, даже если выполнено другое FaultRule, добавьте дочерний элемент<AlwaysEnforce>true</AlwaysEnforce>.
- Если вы хотите, чтобы правило
Шаблон для централизованной, многократно используемой обработки неисправностей
В следующем сообщении сообщества Apigee описывается шаблон централизованной обработки неисправностей без дублирования кода:
Шаблон обработки ошибок для прокси-серверов Apigee
Создание правил ошибок
Чтобы добавить правило FaultRule, необходимо отредактировать XML-конфигурацию ProxyEndpoint или TargetEndpoint. Это можно сделать с помощью интерфейса Edge UI на панели «Код» в представлении «Разработка» для прокси-сервера API или в XML-файле, определяющем ProxyEndpoint или TargetEndpoint.
Если вы создаёте FaultRule в пользовательском интерфейсе управления, сначала создайте политики, которые вы хотите выполнить, а затем добавьте их в конфигурацию FaultRule. (Если вы попытаетесь сохранить FaultRule, ссылающийся на политику, которая ещё не создана, в пользовательском интерфейсе возникнет ошибка.)
Добавление политик в FaultRule
Хотя в FaultRule можно задать любую политику, для генерации настраиваемого ответного сообщения об ошибке обычно используется политика AssignMessage . AssignMessage позволяет настроить HTTP-ответ с полезной нагрузкой, кодом состояния HTTP, заголовками и элементами фразы-причины.
В примере ниже показана типичная конфигурация политики AssignMessage :
<AssignMessage name="fault_invalidkey"> <Set> <Payload contentType="text/plain">Contact support at support@mycompany.com.</Payload> <StatusCode>401</StatusCode> <ReasonPhrase>Unauthorized</ReasonPhrase> </Set> <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables> </AssignMessage>
Теперь вы можете использовать эту политику в вашем правиле FaultRule. Обратите внимание, как вы ссылаетесь на политику AssignMessage по имени в правиле FaultRule:
<ProxyEndpoint name="default">
...
<FaultRules>
<FaultRule name="invalid_key_rule">
<Step>
<Name>fault_invalidkey</Name>
</Step>
<Condition>(fault.name = "InvalidApiKey")</Condition>
</FaultRule>
</FaultRules>
</ProxyEndpoint>При развертывании указанной выше конфигурации прокси-сервер API будет выполнять политику AssignMessage, называемую fault_invalidkey всякий раз, когда приложение представляет недействительный ключ API.
В FaultRule можно выполнить несколько политик, как показано в следующем примере:
<ProxyEndpoint name="default">
...
<FaultRules>
<FaultRule name="invalid_key_rule">
<Step>
<Name>policy1</Name>
</Step>
<Step>
<Name>policy2</Name>
</Step>
<Step>
<Name>policy3</Name>
</Step>
<Condition>(fault.name = "InvalidApiKey")</Condition>
</FaultRule>
</FaultRules>
</ProxyEndpoint>Политики выполняются в заданном порядке. Например, можно использовать политику MessageLogging , политику ExtractVariables , политику AssignMessage или любую другую политику в правиле FaultRule. Обратите внимание, что обработка правила FaultRule немедленно останавливается в любой из следующих ситуаций:
- Любая политика в FaultRule приводит к ошибке
- Любая из политик в FaultRule имеет тип RaiseFault
Определение пользовательского сообщения об ошибке, возвращаемого из FaultRule
Рекомендуется четко определить ответы на ошибки в ваших API. Это позволит предоставлять клиентам согласованную и полезную информацию.
В следующем примере политики AssignMessage теги <Payload> , <StatusCode> и <ReasonPhase> используются для определения настраиваемого ответа об ошибке, отправляемого клиенту при ошибке InvalidApiKey (см. предыдущий пример FaultRules).
<AssignMessage name="fault_invalidkey"> <Set> <Payload contentType="text/plain">You have attempted to access a resource without the correct authorization. Contact support at support@mycompany.com.</Payload> <StatusCode>401</StatusCode> <ReasonPhrase>Unauthorized</ReasonPhrase> </Set> <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables> </AssignMessage>
Этот ответ включает в себя:
- Полезная нагрузка, содержащая сообщение об ошибке и адрес электронной почты для обращения в службу поддержки.
- Код статуса HTTP, возвращенный в ответе.
- Фраза с причиной, представляющая собой краткое описание ошибки.
Создание DefaultFaultRule
Правило DefaultFaultRule действует как обработчик исключений для любой ошибки, которая явно не обрабатывается другим правилом FaultRule. Если условия всех правил FaultRule не соответствуют ошибке, то правило DefaultFaultRule обрабатывает её. Чтобы включить обработку ошибок по умолчанию, добавьте тег <DefaultFaultRule> в качестве дочернего элемента конечной точки ProxyEndpoint или TargetEndpoint.
Например, конфигурация TargetEndpoint ниже определяет DefaultFaultRule, которое вызывает политику с именем ReturnGenericError:
<TargetEndpoint name="default">
...
<FaultRules>
...
</FaultRules>
<DefaultFaultRule name="fault-rule">
<Step>
<Name>ReturnGenericError</Name>
</Step>
</DefaultFaultRule>
<HTTPTargetConnection>
<URL>http://mocktarget.apigee.net</URL>
</HTTPTargetConnection>
</TargetEndpoint>Правило DefaultFaultRule обычно используется для возврата общего сообщения об ошибке в случае любой непредвиденной ошибки, например, сообщения с контактной информацией для службы технической поддержки. Этот ответ по умолчанию служит двум целям: предоставляет удобную для разработчиков информацию и скрывает URL-адреса бэкенда или другую информацию, которая может быть использована для взлома системы.
Например, вы определяете следующую политику AssignMessage для возврата общей ошибки:
<AssignMessage name="ReturnGenericError"> <Set> <Payload type="text/plain">SERVICE UNAVAILABLE. PLEASE CONTACT SUPPORT: support@company.com.</Payload> </Set> </AssignMessage>
Include the <AlwaysEnforce> element in the <DefaultFaultRule> tag to execute the DefaultFaultRule for every error, even if another FaultRule has already been executed. The DefaultFaultRule is always the last FaultRule to execute:
<DefaultFaultRule name="fault-rule">
<Step>
<Name>ReturnGenericError</Name>
</Step>
<AlwaysEnforce>true</AlwaysEnforce>
</DefaultFaultRule>One use of the DefaultFaultRule is to determine the type of error that occurs when you otherwise cannot determine it. For example, your API proxy is failing for an error that you cannot determine. Use the DefaultFaultRule to invoke the following AssignMessage policy. This policy writes the fault.name value to a header named DefaultFaultHeader in the response:
<AssignMessage async="false" continueOnError="false" enabled="true" name="DefaultFaultRule"> <DisplayName>DefaultFaultRule</DisplayName> <Set> <Headers> <Header name="DefaultFaultHeader">{fault.name}</Header> </Headers> </Set> <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables> <AssignTo createNew="false" transport="http" type="response"/> </AssignMessage>
You can then view the header in the Edge trace tool or on the response to see what caused the error.
Adding message logging to the PostClientFlow
The PostClientFlow is the only flow that executes after the proxy enters the error state. Only the MessageLogging policy can be attached to this flow, which is executed after the response is sent back to the client. Although attaching the MessageLogging policy to this flow is technically not error handling, you can use it to log information in the event of an error. Because it is executed regardless of whether the proxy succeeded or failed, you can put Message Logging policies in the PostClientFlow and be guaranteed that they always execute.
Handling policy faults within the current flow
The examples shown so far all use a FaultRule on the ProxyEndpoint or TargetEndpoint to handle any policy errors as part of the error state. That is because the default value of the continueOnError element of a policy is false , meaning that when an error occurs in a policy, control is directed to the error state. Once in the error state, you cannot return control back to the normal pipeline and you typically return some form of error message to the calling app.
However, if you set the continueOnError element to true for a policy, control stays in the current flow and the next policy in the pipeline executes after the policy that caused the error. The advantage to handling the error in the current flow is that you might have a way to recover from the error to complete processing of the request.
Shown below is a VerifyAPIKey policy named verify-api-key with the continueOnError element set to true:
<VerifyAPIKey async="false" continueOnError="true" enabled="true" name="verify-api-key"> <DisplayName>Verify API Key</DisplayName> <APIKey ref="request.queryparam.apikey"/> </VerifyAPIKey>
If the API key is missing or invalid, then the VerifyAPIKey policy sets the oauthV2.verify-api-key.failed variable to true , but processing continues in the current flow.
You then add VerifyAPIKey policy as a step in the PreFlow of the ProxyEndpoint:
<ProxyEndpoint name="default">
...
<PreFlow name="PreFlow">
<Request>
<Step>
<Name>verify-api-key</Name>
</Step>
<Step>
<Name>FaultInFlow</Name>
<Condition>(oauthV2.verify-api-key.failed = "true")</Condition>
</Step>
</Request>
<Response/>
</PreFlow>
</ProxyEndpoint>Notice how the next step in the PreFlow uses a condition to test for the existence of an error. If an error occurred in the VerifAPIKey policy, then the policy named FaultInFlow policy executes. Otherwise, the FaultInFlow policy is skipped. The FaultInFlow policy can do many things, such as logging the error, attempting to fix the error, or performing some other action.
Triggering an error by using the RaiseFault policy
You can use the RaiseFault policy at any time in a flow to trigger an error. When a RaiseFault policy executes, it terminates the current flow and transfers control to the error state.
One use of the RaiseFault policy is to test for a specific condition that another policy might not detect. In the example above, you added a <Condition> tag to a PreFlow <Step> tag that caused the policy FaultInFlow to execute if the condition is met. If FaultInFlow is a RaiseFault policy, then control transfers to the error state. Or, you might insert a RaiseFault policy in a flow to debug and test your FaultRules.
When a RaiseFault policy triggers an error, you can use the following FaultRule and condition to process it:
<FaultRule name="raisefault_rule">
<Step>
<Name>{policy_name}</Name>
</Step>
<Condition>(fault.name = "RaiseFault")</Condition>
</FaultRule>Note that the condition tests for a fault named RaiseFault . The RaiseFault policy always sets the value of fault.name to RaiseFault .
Custom handling of HTTP error codes from the target server
The examples shown in the previous sections apply to errors created by policies. However you can also create a custom response for transport-level errors, meaning HTTP errors returned from the target server. To control the response from an HTTP error, configure a TargetEndpoint to process HTTP response codes.
By default, Edge treats HTTP response codes in the 1xx-3xx range as 'success', and HTTP response codes in the range 4xx-5xx as 'failure'. That means any response from the backend service with an HTTP response code 4xx-5xx automatically invokes the error state, which then returns an error message directly to the requesting client.
You can create custom handlers for any HTTP response codes. For example, you might not want to treat all HTTP response codes in the range 4xx-5xx as 'failure' but only 5xx, or you might want to return custom error messages for HTTP response codes 400 and 500.
In the next example, you use the success.codes property to configure the TargetEndpoint to treat HTTP response codes 400 and 500 as a success, along with the default HTTP codes. By treating those codes as a success, the TargetEndpoint takes over the processing of the response message, instead of invoking the error state:
<TargetEndpoint name="default">
...
<HTTPTargetConnection>
<Properties>
<Property name="success.codes">1xx,2xx,3xx,400,500</Property>
</Properties>
<URL>http://weather.yahooapis.com</URL>
</HTTPTargetConnection>
</TargetEndpoint>As you can see in this example, you can use wildcards to set the success.codes property to a range of values..
Setting the success.codes property overwrites the default values. Therefore, if you want to add HTTP code 400 to the list of default success codes, set this property as:
<Property name="success.codes">1xx,2xx,3xx,400</Property>
But, if you only want HTTP code 400 to be treated as a success code, set the property as:
<Property name="success.codes">400</Property>
You can now define custom handlers for HTTP response codes 400 and 500 to return a customized response message to the requesting app. The following TargetEndpoint uses the policy named ReturnError to handle HTTP 400 and 500 response codes:
<TargetEndpoint name="default">
<PreFlow name="PreFlow">
<Request/>
<Response>
<Step>
<Name>ReturnError</Name>
<Condition>(response.status.code = 400) or (response.status.code = 500)</Condition>
</Step>
</Response>
</PreFlow>
<HTTPTargetConnection>
<Properties>
<Property name="success.codes">1xx,2xx,3xx,400,500</Property>
</Properties>
<URL>http://weather.yahooapis.com</URL>
</HTTPTargetConnection>
</TargetEndpoint>This TargetEndpoint configuration causes the policy called ReturnError to handle the response whenever the TargetEndpoint encounters an HTTP response code of 400 or 500.
Fault taxonomy
API Services organizes faults into the following categories and subcategories.
| Категория | Подкатегория | Fault Name | Описание |
|---|---|---|---|
| Обмен сообщениями | Failures that occur during the message flow (not including policy failures) | ||
| Custom faults | {fault_name} | Any faults explicitly handled by the API proxy using the RaiseFault policy | |
| Коды ответов | InternalServerError, NotFound | HTTP error codes 5xx, 4xx | |
| Routing failures | NoRoutesMatched | Failure in selecting a named TargetEndpoint for a request | |
| Classification failures | Не найдено | Failures caused by a request URI that does not match any BasePath for any ProxyEndpoint configurations (that is, no API proxies match the URL in the client app's request) | |
| Транспорт | HTTP transport-level errors | ||
| Связность | ConnectionRefused, ConnectionReset, ConnectionTimeout | Failures occur while establishing network or transport-level connections | |
| Request validations | ContentLengthMissing, HostHeaderMissing | Faults occur during semantics checks on every request | |
| Response validations | Faults occur during semantics checks on every response | ||
| IO errors | SSLHandshakeError, ReadTimeout, ReadError, WriteTimeout, WriteError, ChunkError | Read/write errors at client or target endpoints, timeouts, TLS/SSL errors, and chunked errors | |
| Система | Undefined runtime errors | ||
| Память | OutOfMemory, GCOverLimit | Memory-related failures | |
| Нить | RogueTaskTerminated | Failures such as termination of run-away tasks | |
| Политика | Faults for each Policy type are defined in the Policy Reference . | ||
An error is always accompanied by a text description of the reason for the failure. When the system raises a fault, a set of attributes are populated to assist in troubleshooting. A fault includes the following information:
- Причина
- User-defined custom attributes
