Как добавить поддержку технологии CORS в прокси-сервер API

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

CORS (совместное использование ресурсов между разными источниками) – это стандартный механизм, который позволяет вызовам JavaScript XMLHttpRequest (XHR), выполняемым на веб-странице, взаимодействовать с ресурсами из доменов, отличных от источника. CORS – это распространенное решение, позволяющее обойти правило одинакового происхождения, которое действует во всех браузерах. Например, если вы выполните вызов XHR к Twitter API из кода JavaScript, выполняемого в браузере, вызов завершится неудачно. Это связано с тем, что домен, с которого страница загружается в ваш браузер, отличается от домена, с которого загружается Twitter API. 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" при создании. Чтобы добавить это правило, установите флажок Добавить заголовки CORS на странице "Безопасность" мастера создания прокси.

Если вы установите этот флажок, в систему будет автоматически добавлено правило Add CORS и прикреплено к предварительному потоку ответов TargetEndpoint, как показано на рисунке ниже.

Добавлены правила CORS для навигатора в разделе &quot;Правила&quot; и прикреплены к предварительному потоку ответов TargetEndpoint на панели справа.

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

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

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

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

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

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

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

Подробнее о предварительных запросах… Кроме того, в интернете можно найти множество статей и блогов, посвященных 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:

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

    <RouteRule name="NoRoute">
        <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
    </RouteRule>
  • Создается поток OptionsPreFlight, который добавляет в поток правило Add 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. Подробную информацию можно найти в файле CORS-Shared-FLow README, который поставляется с примером.