Añadir compatibilidad con CORS a un proxy de APIs

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 ejecutadas en una página web interactúen con recursos de dominios que no son de origen. CORS es una solución que se implementa habitualmente para la política de mismo origen que aplican todos los navegadores. Por ejemplo, si haces una llamada XHR a la API de Twitter desde un código JavaScript que se ejecuta en tu navegador, la llamada fallará. Esto se debe a que el dominio que sirve la página a tu navegador no es el mismo que el que sirve la API de Twitter. CORS ofrece una solución a este problema, ya que permite que los servidores habiliten esta opción si quieren ofrecer el uso compartido de recursos entre dominios.

Caso práctico habitual de 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 del 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 (un navegador en este caso) y la API de backend (el servicio). Como el proxy de API se ejecuta en el servidor, no en un navegador, puede llamar al servicio correctamente. Después, solo tienes que adjuntar encabezados CORS a la respuesta TargetEndpoint. Siempre que el navegador admita CORS, estos encabezados indicarán al navegador que puede flexibilizar su política de mismo origen, lo que permitirá que la llamada a la API entre orígenes se realice correctamente.

Una vez que se haya creado el proxy con compatibilidad con CORS, puedes llamar a la URL del proxy de la API en lugar del servicio de backend en el código del lado 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>

Vincular la política de CORS al PreFlow de la solicitud de ProxyEndpoint

Asociar una política de uso compartido de recursos entre orígenes (CORS) a un nuevo proxy de API

Puede añadir compatibilidad con CORS a un proxy de API adjuntando una política Add CORS al proxy de API de las siguientes formas:

  • Cuando creas la política seleccionando la casilla Añadir encabezados CORS en la página Seguridad del asistente Crear un proxy
  • Añadiéndola más tarde desde el cuadro de diálogo Añadir política

Cuando añades la política de CORS seleccionando la casilla, se añade automáticamente al sistema una política llamada Add CORS, que se adjunta al preflujo de solicitud TargetEndpoint.

La política Añadir CORS añade los encabezados correspondientes a la respuesta. Básicamente, las cabeceras indican al navegador con qué orígenes compartirá sus recursos, qué métodos acepta, etc. Puedes consultar más información sobre estos encabezados CORS en la recomendación del W3C sobre el uso compartido de recursos entre orígenes.

Debería modificar la política de la siguiente manera:

  • Añade los encabezados content-type y authorization (necesarios para admitir la autenticación básica o OAuth2) al encabezado Access-Control-Allow-Headers, como se muestra en el fragmento de código de abajo.
  • Para la autenticación OAuth2, es posible que tengas que tomar medidas para corregir el comportamiento no conforme a 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>

Añadir encabezados CORS a un proxy

Nuevo editor de proxies

Para añadir la política de CORS a un proxy de API, sigue estos pasos:

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

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

  2. Selecciona el proxy de API al que quieras añadir 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, haga clic en el botón + de la fila Políticas.
  5. En el cuadro de diálogo Crear política, haga clic en el campo Seleccionar tipo de política, desplácese hacia abajo hasta Seguridad y seleccione CORS.

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

  7. En el panel de la izquierda, haga clic en PreFlow, en Target Endpoints > default.
  8. En el panel Solicitud, situado en la parte inferior derecha del editor visual, haz clic en el botón + junto a PreFlow.
  9. En el cuadro de diálogo Añadir política, selecciona la política CORS.
  10. Haga clic en Añadir para adjuntar la política.

Editor de proxies clásico

Para añadir la política de CORS a un proxy de API, sigue estos pasos:

  1. Inicia sesión en la interfaz de usuario de Apigee.
  2. Seleccione Desarrollar > Proxies de API en la barra de navegación de la izquierda.
  3. Si ves el botón Probar ahora, haz clic en él para mostrar la nueva vista Desarrollo.

    A continuación, se muestra la vista Desarrollar.

    Vista de desarrollo en el editor de proxies

  4. Selecciona el proxy de API al que quieras añadir 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 de navegación de la izquierda, haga clic en PreFlow en Target Endpoints > default.
  7. Haz clic en el botón + Paso de la parte superior, que corresponde a Request PreFlow. Se muestra 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 haz clic en Añadir.

Gestionar solicitudes preparatorias de CORS

Verificación previa de CORS se refiere al envío de una solicitud a un servidor para comprobar si admite CORS. Las respuestas preparatorias típicas incluyen los orígenes desde los que el servidor aceptará solicitudes CORS, una lista de métodos HTTP admitidos para las solicitudes CORS, los encabezados que se pueden usar como parte de la solicitud de recursos, el tiempo máximo que se almacenará en caché la respuesta preparatoria y otros. Si el servicio no indica que admite CORS o no quiere aceptar solicitudes entre orígenes del origen del cliente, se aplicará la política entre orígenes del navegador y se producirá un error en cualquier solicitud entre dominios que haga el cliente para interactuar con los recursos alojados en ese servidor.

Normalmente, las solicitudes preparatorias de CORS se realizan con el método HTTP OPTIONS. Cuando un servidor que admite CORS recibe una solicitud OPTIONS, devuelve un conjunto de encabezados CORS al cliente que indican su nivel de compatibilidad con CORS. Como resultado de esta negociación, el cliente sabe qué puede solicitar del dominio que no es el de origen.

Para obtener más información sobre las comprobaciones previas, consulta la recomendación del W3C sobre el intercambio de recursos de origen cruzado. Además, hay numerosos blogs y artículos sobre CORS que puedes consultar.

Apigee no incluye una solución de solicitud preparatoria de CORS predefinida, pero se puede implementar, tal como se describe en esta sección. El objetivo es que el proxy evalúe una solicitud OPTIONS en un flujo condicional. El proxy puede enviar una respuesta adecuada al cliente.

Veamos un flujo de ejemplo y, después, analicemos las partes que gestionan 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 con un destino NULL y una condición para la solicitud OPTIONS. Ten en cuenta que no se ha especificado ningún TargetEndpoint. Si se recibe la solicitud OPTIONS y los encabezados de solicitud Origin y Access-Control-Request-Method no son nulos, el proxy devuelve inmediatamente los encabezados CORS en una respuesta al cliente (sin pasar por el destino "backend" predeterminado). Para obtener más información 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 añade una política CORS, que contiene los encabezados CORS, al flujo si se recibe una solicitud OPTIONS y los encabezados de solicitud Origin y Access-Control-Request-Method 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>