Aggiunta del supporto CORS a un proxy API

Stai visualizzando la documentazione di Apigee Edge.
Vai alla documentazione di Apigee X.
informazioni

CORS (Cross-Origin Resource Sharing) è un meccanismo standard che consente alle chiamate JavaScript XMLHttpRequest (XHR) eseguite in una pagina web di interagire con le risorse dei domini non origini. CORS è una soluzione comunemente implementata per il "criterio della stessa origine" applicato da tutti i browser. Ad esempio, se effettui una chiamata XHR all'API Twitter dal codice JavaScript in esecuzione nel browser, la chiamata avrà esito negativo. Questo perché il dominio che pubblica la pagina nel tuo browser non corrisponde a quello che pubblica l'API Twitter. CORS offre una soluzione a questo problema consentendo ai server di eseguire l'attivazione se vogliono fornire la condivisione delle risorse tra origini.

Video: guarda un breve video per scoprire come attivare CORS su un proxy API.

Caso d'uso tipico per CORS

Il seguente codice JQuery chiama un servizio di destinazione fittizio. Se viene eseguita nel contesto di un browser (una pagina web), la chiamata non andrà a buon fine a causa del criterio della stessa origine:

<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 soluzione a questo problema è creare un proxy API Apigee che chiami l'API del servizio sul backend. Ricorda che Edge si trova tra il client (in questo caso un browser) e l'API di backend (il servizio). Poiché il proxy API viene eseguito sul server e non in un browser, è in grado di chiamare il servizio correttamente. Quindi, devi solo collegare le intestazioni CORS alla risposta di TargetEndpoint. Finché il browser supporta CORS, queste intestazioni segnalano al browser che è possibile "rilassare" il criterio della stessa origine, in modo che la chiamata API multiorigine abbia esito positivo.

Dopo aver creato il proxy con supporto CORS, puoi chiamare l'URL del proxy API anziché il servizio di backend nel codice lato client. Ad esempio:

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

Collegamento di un criterio di aggiunta CORS a un nuovo proxy API

Puoi aggiungere il supporto CORS a un proxy API collegando un criterio "Aggiungi CORS" al proxy API quando lo crei. Per aggiungere questo criterio, seleziona la casella di controllo Aggiungi intestazioni CORS nella pagina Sicurezza della procedura guidata Crea un proxy.

Quando selezioni questa casella di controllo, un criterio denominato Aggiungi CORS viene aggiunto automaticamente al sistema e associato al preflusso della risposta TargetEndpoint, come mostrato nella figura seguente:

Aggiungi il criterio CORS aggiunto al navigatore nella sezione Criteri e allegato al preflusso della risposta TargetEndpoint nella panoramica a destra

Il criterio Aggiungi CORS viene implementato come un criterioAssignMessage, che aggiunge le intestazioni appropriate alla risposta. Fondamentalmente, le intestazioni consentono al browser di sapere con quali origini condividerà le sue risorse, quali metodi accetta e così via. Per saperne di più su queste intestazioni CORS, consulta il consiglio W3C per la condivisione delle risorse tra origini.

È necessario modificare il criterio come segue:

  • Aggiungi le intestazioni content-type e authorization (necessarie per supportare l'autenticazione di base o OAuth2) all'intestazione Access-Control-Allow-Headers, come mostrato nell'estratto di codice riportato di seguito.
  • Per l'autenticazione OAuth2, potresti dover seguire alcuni passaggi per correggere il comportamento non conforme alla RFC.
  • È consigliabile utilizzare <Set> per impostare le intestazioni CORS anziché <Add>, come mostrato nell'estratto di seguito. Quando utilizzi <Add>, se l'intestazione Access-Control-Allow-Origin esiste già, riceverai il seguente errore:

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

    Per maggiori informazioni, consulta la sezione Errore CORS : l'intestazione contiene più valori "*, *", ma è consentito un solo valore.

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

Aggiunta di intestazioni CORS a un proxy esistente

Devi creare manualmente un nuovo criterio Assegna messaggio e copiare al suo interno il codice del criterio Aggiungi criterio CORS elencato nella sezione precedente. Quindi, collega il criterio al pre-flusso di risposta di TargetEndpoint del proxy API. Puoi modificare i valori dell'intestazione in base alle tue esigenze. Per ulteriori informazioni sulla creazione e sul collegamento dei criteri, vedi Che cos'è un criterio?.

Gestione delle richieste preflight CORS

Preflight CORS si riferisce all'invio di una richiesta a un server per verificare se supporta CORS. Le tipiche risposte preflight includono le origini da cui il server accetterà le richieste CORS, un elenco di metodi HTTP supportati per le richieste CORS, le intestazioni che possono essere utilizzate come parte della richiesta di risorsa, il tempo massimo della risposta preflight che verrà memorizzata nella cache e altro ancora. Se il servizio non indica il supporto CORS o non vuole accettare richieste multiorigine dall'origine del client, verrà applicato il criterio multiorigine del browser e le eventuali richieste interdominio effettuate dal client per interagire con le risorse ospitate su quel server avranno esito negativo.

In genere, le richieste preflight CORS vengono effettuate con il metodo HTTP OPTIONS. Quando un server che supporta CORS riceve una richiesta OPTIONS, restituisce al client un insieme di intestazioni CORS che indicano il livello di supporto CORS. Come risultato di questo handshake, il client sa cosa può richiedere dal dominio non origine.

Per saperne di più sul preflight, consulta il consiglio W3C sulla condivisione delle risorse tra origini. Sono inoltre disponibili numerosi blog e articoli su CORS a cui puoi fare riferimento.

Apigee non include una soluzione preflight CORS predefinita, ma è possibile implementarla, come descritto in questa sezione. L'obiettivo è che il proxy valuti una richiesta OPTIONS in un flusso condizionale. Il proxy può quindi inviare una risposta appropriata al client.

Diamo un'occhiata a un flusso di esempio e poi parliamo delle parti che gestiscono la richiesta preflight:

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

Le parti principali di questo ProxyEndpoint sono le seguenti:

  • Viene creata una routeRule per una destinazione NULL con una condizione per la richiesta OPTIONS. Tieni presente che non è stato specificato alcun TargetEndpoint. Se la richiesta OPTIONS viene ricevuta e le intestazioni delle richieste Origin e Access-Control-Request-Method non sono null, il proxy restituisce immediatamente le intestazioni CORS in una risposta al client, ignorando la destinazione effettiva di "backend" predefinita. Per maggiori dettagli sulle condizioni di flusso e RouteRule, consulta Condizioni con variabili di flusso.

    <RouteRule name="NoRoute">
        <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
    </RouteRule>
    
  • Viene creato un flusso opzioniPreFlight che aggiunge al flusso un criterio Aggiungi CORS, contenente le intestazioni CORS, se viene ricevuta una richiesta OPTIONS e le intestazioni delle richieste Origin e Access-Control-Request-Method non sono null.

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

Utilizzo della soluzione CORS di esempio

Una soluzione CORS di esempio, implementata come flusso condiviso, è disponibile su GitHub. Importa il pacchetto di flussi condivisi nel tuo ambiente e collegalo utilizzando gli hook di flusso o direttamente ai flussi del proxy API. Per maggiori dettagli, consulta il file CORS-Shared-FLow README fornito con l'esempio.