Agrega compatibilidad con CORS a un proxy de API

Esta página se aplica a Apigee y Apigee Hybrid.

Consulta la documentación de Apigee Edge.

CORS (uso compartido de recursos entre dominios) es un mecanismo estándar que permite que las llamadas XMLHttpRequest (XHR) de JavaScript que se ejecutan en una página web interactúen con recursos de dominios que no son de origen. CORS es una solución implementada con frecuencia en la política del mismo origen que aplican todos los navegadores. Por ejemplo, si realizas una llamada XHR a la API de Twitter desde el código JavaScript que se ejecuta en el navegador, la llamada fallará. Esto se debe a que el dominio que entrega la página a tu navegador no es el mismo dominio que entrega la API de Twitter. CORS proporciona una solución a este problema, ya que permite que los servidores lo habiliten si desean proporcionar uso compartido de recursos entre dominios.

Caso de uso típico para CORS

El siguiente código de JQuery llama a un servicio de destino ficticio. Si se ejecuta desde el contexto de un navegador (una página web), la llamada fallará debido a la política de mismo origen:

<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>

Una solución a este problema es crear un proxy de API de Apigee que llame a la API de servicio en el backend. Recuerda que Apigee se encuentra entre el cliente (en este caso, un navegador) y la API de backend (el servicio). Debido a que el proxy de API se ejecuta en el servidor, no en un navegador, puede llamar al servicio de forma correcta. Luego, todo lo que necesitas hacer es adjuntar encabezados de CORS a la respuesta TargetEndpoint. Siempre que el navegador admita CORS, estos encabezados indican al navegador que está bien disminuir la rigurosidad de su política de mismo origen, lo que permite que la llamada a la API entre dominios se realice correctamente.

Una vez que se crea el proxy con la compatibilidad con CORS, puedes llamar a la URL del proxy de la API en lugar del servicio de backend en tu código del cliente. Por ejemplo:

<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>

Conecta la política de CORS al flujo previo de solicitud del ProxyEndpoint

Conecta una política Agregar CORS a un nuevo proxy de API

Para agregar la compatibilidad con CORS a un proxy de API, puedes adjuntar una política de Agregar CORS al proxy de API de las siguientes maneras:

  • Cuando creas la política seleccionando la casilla de verificación Agregar encabezados de CORS en la página Seguridad del asistente Compilar un proxy.
  • Cuando los agregas más tarde desde el cuadro de diálogo Agregar política.

Cuando marcas la casilla de verificación para agregar la política de CORS, una política llamada Agregar CORS se agrega de forma automática al sistema y se adjunta al flujo previo de la solicitud de TargetEndpoint.

La política Agregar CORS agrega los encabezados adecuados a la respuesta. Básicamente, los encabezados informan al navegador de los orígenes con los que compartirá sus recursos, qué métodos acepta, etc. Puedes obtener más información sobre estos encabezados de CORS en la Recomendación de uso compartido de recursos entre dominios de W3C.

Debes modificar la política de la siguiente manera:

  • Agrega los encabezados content-type y authorization (obligatorios para admitir OAuth2 o la autenticación básica) al encabezado Access-Control-Allow-Headers, como se muestra en el extracto de código que aparece a continuación.
  • Para la autenticación OAuth2, es posible que debas tomar medidas para corregir el comportamiento no compatible con RFC.
<CORS continueOnError="false" enabled="true" name="add-cors">
    <DisplayName>Add CORS</DisplayName>
    <AllowOrigins>{request.header.origin}</AllowOrigins>
    <AllowMethods>GET, PUT, POST, DELETE</AllowMethods>
    <AllowHeaders>origin, x-requested-with, accept, content-type, authorization</AllowHeaders>
    <ExposeHeaders>*</ExposeHeaders>
    <MaxAge>3628800</MaxAge>
    <AllowCredentials>false</AllowCredentials>
    <GeneratePreflightResponse>true</GeneratePreflightResponse>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</CORS>

Agrega encabezados CORS a un proxy existente

Editor de proxies nuevo

Para agregar la política de CORS a un proxy de API existente, haz lo siguiente:

  1. Si usas la IU de Apigee en la consola de Cloud, selecciona Desarrollo de proxy > Proxies de API.

    Si usas la IU clásica de Apigee, selecciona Desarrollar > Proxies de API y, en el panel Proxies, selecciona el entorno para el proxy.

  2. Selecciona el proxy de API al que deseas agregar la política de CORS.
  3. En el editor del nuevo proxy de API, haz clic en la pestaña Desarrollar.
  4. En el panel de la izquierda, haz clic en el botón + en la fila Políticas.
  5. En el cuadro de diálogo Crear política, haz clic en el campo Seleccionar tipo de política, desplázate hacia abajo hasta Seguridad y selecciona CORS.

  6. Ingresa los detalles de la política y haz clic en Crear.

  7. En el panel del navegador de la izquierda, haz clic en PreFlow en Extremos del proxy > predeterminado.
  8. Selecciona Extremos de Proxy > configuración predeterminada> PreFlow en el panel izquierdo:

    Extremos de destino para PreFlow seleccionados en el Explorador de proxy.

  9. Haz clic en el botón + junto a PreFlow en el panel Respuesta en la esquina inferior derecha del editor visual:

    Haz clic en el botón + junto al PreFlow en el panel Respuesta.

  10. En el cuadro de diálogo Agregar paso de la política, selecciona la política CORS.
  11. Haz clic en Agregar para adjuntar la política.

Editor de proxies clásico

Para agregar la política de CORS a un proxy de API existente, haz lo siguiente:

  1. Accede a la IU de Apigee.
  2. Selecciona Desarrollar > Proxies de API en la barra de navegación izquierda.
  3. Si ves el botón Probar ahora, haz clic en él para mostrar la vista nueva Desarrollar.

    La vista Desarrollar se muestra a continuación.

    Desarrolla la vista en el editor de proxy

  4. Selecciona el proxy de API al que deseas agregar la política de CORS.
  5. En el editor del nuevo proxy de API, haz clic en la pestaña Desarrollar:
  6. En el panel del navegador de la izquierda, haz clic en Flujo previo en Extremos del proxy > predeterminado.
  7. Haz clic en el botón superior + Paso (+ Step), que corresponde a solicitud de flujo previo. Esto mostrará una lista categorizada de todas las políticas que puedes crear.
  8. Selecciona CORS en la categoría Seguridad.
  9. Proporciona un nombre, como Add CORS y, luego, haz clic en Agregar.

Controla las solicitudes de comprobación previa de CORS

La comprobación previa de CORS hace referencia al envío de una solicitud a un servidor para que verifique si es compatible con CORS. Las respuestas de comprobación previa típicas incluyen de qué orígenes el servidor acepta las solicitudes CORS, una lista de métodos HTTP compatibles con solicitudes CORS, encabezados que se pueden usar como parte de la solicitud de recursos, el tiempo máximo que la respuesta de comprobación previa se almacena en caché y otros. Si el servicio no indica la compatibilidad con CORS o no desea aceptar solicitudes de origen cruzado desde el origen del cliente, se aplicará la política de origen cruzado del navegador y fallará cualquier solicitud de dominio cruzado que haga el cliente para interactuar con los recursos alojados en ese servidor.

Por lo general, las solicitudes preliminares de CORS se realizan con el método OPTIONS DE HTTP. Cuando un servidor que admite CORS recibe una solicitud de OPTIONS, muestra un conjunto de encabezados de CORS al cliente que indica su nivel de compatibilidad con CORS. Como resultado de este protocolo de enlace, el cliente sabe qué se le permite solicitar desde el dominio que no es de origen.

Para obtener más información sobre comprobación previa, consulta la Recomendación del uso compartido de recursos entre dominios W3C. Hay varios blogs y artículos sobre CORS que puedes consultar.

Apigee no incluye una solución preliminar de CORS lista para usar, pero es posible implementarla, como se describe en esta sección. El objetivo es que el proxy evalúe una solicitud de OPTIONS en un flujo condicional. Luego, puede enviar una respuesta adecuada al cliente.

Analicemos un flujo de muestra y, luego, veamos las partes que manejan la solicitud de comprobación previa:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProxyEndpoint name="default">
    <Description/>
    <Flows>
        <Flow name="OptionsPreFlight">
            <Request>
                <Step>
                    <Name>add-cors</Name>
                </Step>
            </Request>
            <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>

Las partes clave de este ProxyEndpoint son las siguientes:

  • Se crea una RouteRule en un objetivo NULL con una condición para la solicitud de OPTIONS. Ten en cuenta que no hay ningún TargetEndpoint especificado. Si se recibe la solicitud de OPTIONS, y los encabezados de la solicitud de origen y Access-Control-Request-Method no son nulos, el proxy muestra de inmediato los encabezados de CORS en una respuesta al cliente (si se omite el destino “backend” predeterminado). Para obtener detalles sobre las condiciones de flujo y RouteRule, consulta Condiciones con variables de flujo.
    <RouteRule name="NoRoute">
        <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
    </RouteRule>
    
  • Se crea un flujo OptionsPreFlight que agrega una política Add CORS, que contiene los encabezados CORS, al flujo si se recibe una solicitud OPTIONS y los encabezados de solicitud de origen y acceso-Control-Request no son nulos.
     <Flow name="OptionsPreFlight">
                <Request>
                    <Step>
                        <Name>add-cors</Name>
                    </Step>
                </Request>
                <Response/>
            <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
     </Flow>