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

Когда вы устанавливаете этот флажок, в систему автоматически добавляется политика Add 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 к существующему прокси

Вам необходимо вручную создать новую политику Assign Message и скопировать в нее код для политики Add 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, который добавляет политику 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. Дополнительные сведения см. в файле README CORS-Shared-Flow, прилагаемом к образцу.