Добавление поддержки CORS в прокси API

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

CORS (совместное использование ресурсов между источниками) — это стандартный механизм, который позволяет вызовам JavaScript XMLHttpRequest (XHR), выполняемым на веб-странице, взаимодействовать с ресурсами из доменов, не являющихся источниками. CORS — это широко распространенное решение « политики одного и того же происхождения », которая применяется всеми браузерами. Например, если вы сделаете вызов XHR к API Twitter из кода JavaScript, выполняющегося в вашем браузере, вызов завершится неудачно. Это связано с тем, что домен, обслуживающий страницу в вашем браузере, не совпадает с доменом, обслуживающим API Twitter. CORS обеспечивает решение этой проблемы, позволяя серверам «согласиться», если они хотят обеспечить совместное использование ресурсов между источниками.

Видео. Посмотрите короткое видео, чтобы узнать, как включить CORS на прокси-сервере API.

Типичный вариант использования CORS

Следующий код JQuery вызывает фиктивную целевую службу. Если он выполняется из контекста браузера (веб-страницы), вызов завершится неудачей из-за политики того же источника:

<script>
var url = "http://service.example.com";
$(document).ready(function(){
  $("button").click(function(){
    $.ajax({
        type:"GET",
        url:url,
        async:true,
        dataType: "json",
           success: function(json) {
              // Parse the response.
              // Do other things.
           },
           error: function(xhr, status, err) {
              // This is where we end up!
            }
    });
  });
});
</script>

Одним из решений этой проблемы является создание прокси-сервера API Apigee, который вызывает API службы на серверной стороне. Помните, что Edge находится между клиентом (в данном случае браузером) и серверным API (сервисом). Поскольку прокси-сервер API выполняется на сервере, а не в браузере, он может успешно вызвать службу. Затем все, что вам нужно сделать, это прикрепить заголовки CORS к ответу TargetEndpoint. Пока браузер поддерживает CORS, эти заголовки сигнализируют браузеру, что можно «ослабить» свою политику одного и того же источника, позволяя успешному вызову API между источниками.

После создания прокси-сервера с поддержкой CORS вы можете вызвать URL-адрес прокси-сервера API вместо внутренней службы в клиентском коде. Например:

<script>
var url = "http://myorg-test.apigee.net/v1/example";
$(document).ready(function(){
  $("button").click(function(){
    $.ajax({
        type:"GET",
        url:url,
        async:true,
        dataType: "json",
           success: function(json) {
              // Parse the response.
              // Do other things.
           },
           error: function(xhr, status, err) {
              // This time, we do not end up here!
            }
    });
  });
});
</script>

Прикрепление политики добавления CORS к новому прокси-серверу API

Вы можете добавить поддержку CORS к прокси-серверу API, прикрепив политику «Добавить CORS» к прокси-серверу API при его создании. Чтобы добавить эту политику, установите флажок «Добавить заголовки CORS» на странице «Безопасность» мастера создания прокси-сервера.

Когда вы устанавливаете этот флажок, политика под названием «Добавить CORS» автоматически добавляется в систему и прикрепляется к предварительному потоку ответа TargetEndpoint, как показано на следующем рисунке:

Добавьте политику CORS, добавленную в навигатор в разделе «Политики» и прикрепленную к предварительному потоку ответа TargetEndpoint на правой панели.

Политика Add CORS реализована как политика AssignMessage , которая добавляет в ответ соответствующие заголовки. По сути, заголовки сообщают браузеру, с какими источниками он будет делиться своими ресурсами, какие методы он принимает и так далее. Подробнее об этих заголовках CORS можно прочитать в Рекомендации W3C по совместному использованию ресурсов между источниками .

Вам следует изменить политику следующим образом:

  • Добавьте заголовки content-type и authorization (необходимые для поддержки базовой аутентификации или OAuth2) в заголовок Access-Control-Allow-Headers , как показано в фрагменте кода ниже.
  • Для аутентификации OAuth2 вам может потребоваться предпринять шаги для исправления поведения, не соответствующего RFC .
  • Рекомендуется использовать <Set> для установки заголовков CORS вместо <Add> , как показано во фрагменте ниже. Если при использовании <Add> заголовок Access-Control-Allow-Origin уже существует, вы получите следующую ошибку:

    The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed.

    Дополнительные сведения см. в разделе Ошибка CORS: заголовок содержит несколько значений «*, *», но разрешено только одно .

<AssignMessage async="false" continueOnError="false" enabled="true" name="add-cors">
    <DisplayName>Add CORS</DisplayName>
    <FaultRules/>
    <Properties/>
    <Set>
        <Headers>
            <Header name="Access-Control-Allow-Origin">{request.header.origin}</Header>
            <Header name="Access-Control-Allow-Headers">origin, x-requested-with, accept, content-type, authorization</Header>
            <Header name="Access-Control-Max-Age">3628800</Header>
            <Header name="Access-Control-Allow-Methods">GET, PUT, POST, DELETE</Header>
        </Headers>
    </Set>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <AssignTo createNew="false" transport="http" type="response"/>
</AssignMessage>

Добавление заголовков CORS в существующий прокси

Вам необходимо вручную создать новую политику назначения сообщений и скопировать в нее код политики добавления CORS, указанный в предыдущем разделе. Затем прикрепите политику к предварительному потоку ответа TargetEndpoint прокси-сервера API. При необходимости вы можете изменить значения заголовка. Дополнительные сведения о создании и присоединении политик см. в разделе Что такое политика? .

Обработка предварительных запросов CORS

Предварительная проверка CORS означает отправку запроса на сервер, чтобы проверить, поддерживает ли он CORS. Типичные предварительные ответы включают в себя информацию о том, от каких источников сервер будет принимать запросы CORS, список методов HTTP, которые поддерживаются для запросов CORS, заголовки, которые можно использовать как часть запроса ресурса, максимальное время кэширования предполетного ответа и другие. Если служба не указывает поддержку CORS или не желает принимать запросы между источниками от источника клиента, будет применяться политика браузера между источниками, и любые междоменные запросы, сделанные от клиента для взаимодействия с ресурсами, размещенными на этот сервер выйдет из строя.

Обычно предварительные запросы CORS выполняются с помощью метода HTTP OPTIONS. Когда сервер, поддерживающий CORS, получает запрос OPTIONS, он возвращает клиенту набор заголовков CORS, которые указывают уровень поддержки CORS. В результате этого рукопожатия клиент узнает, что ему разрешено запрашивать из неисходного домена.

Дополнительную информацию о предварительной проверке можно найти в Рекомендации W3C по совместному использованию ресурсов между источниками . Кроме того, вы можете обратиться к многочисленным блогам и статьям о CORS.

Apigee не включает готовое решение CORS для предварительной проверки, но его можно реализовать, как описано в этом разделе. Цель состоит в том, чтобы прокси-сервер оценил запрос OPTIONS в условном потоке. Затем прокси-сервер может отправить соответствующий ответ обратно клиенту.

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

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProxyEndpoint name="default">
    <Description/>
    <Flows>
        <Flow name="OptionsPreFlight">
            <Request/>
            <Response>
                <Step>
                    <Name>add-cors</Name>
                </Step>
            </Response>
        <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
        </Flow>
    </Flows>

    <PreFlow name="PreFlow">
        <Request/>
        <Response/>

    </PreFlow>
    <HTTPProxyConnection>
        <BasePath>/v1/cnc</BasePath>
        <VirtualHost>default</VirtualHost>
        <VirtualHost>secure</VirtualHost>
    </HTTPProxyConnection>
    <RouteRule name="NoRoute">
        <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
    </RouteRule>
    <RouteRule name="default">
        <TargetEndpoint>default</TargetEndpoint>
   </RouteRule>
   <PostFlow name="PostFlow">
        <Request/>
        <Response/>
    </PostFlow>
</ProxyEndpoint>

Ключевые части ProxyEndpoint следующие:

  • RouteRule создается для цели NULL с условием для запроса OPTIONS. Обратите внимание, что TargetEndpoint не указан. Если запрос OPTIONS получен и заголовки запроса Origin и Access-Control-Request-Method не равны нулю, прокси-сервер немедленно возвращает заголовки CORS в ответ клиенту (минуя фактическую цель «внутреннюю часть» по умолчанию). Дополнительные сведения об условиях потока и RouteRule см. в разделе Условия с переменными потока .

    <RouteRule name="NoRoute">
        <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
    </RouteRule>
    
  • Создается поток OptionsPreFlight, который добавляет в поток политику добавления CORS, содержащую заголовки CORS, если получен запрос OPTIONS, а заголовки запроса Origin и Access-Control-Request-Method не равны нулю.

     <Flow name="OptionsPreFlight">
                <Request/>
                <Response>
                    <Step>
                        <Name>add-cors</Name>
                    </Step>
                </Response>
            <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
     </Flow>
    

Использование примера решения CORS

Пример решения CORS, реализованный как общий поток, доступен на GitHub . Импортируйте пакет общего потока в свою среду и прикрепите его с помощью перехватчиков потоков или непосредственно к потокам прокси-сервера API. Дополнительные сведения см. в файле README CORS-Shared-FLow, поставляемом с образцом.