Antipattern: accedere in modo errato a intestazioni HTTP multivalore in un proxy API

Stai visualizzando la documentazione di Apigee e Apigee hybrid.
Visualizza la documentazione di Apigee Edge.

Le intestazioni HTTP sono le coppie nome-valore che consentono alle applicazioni client e ai servizi di backend di trasmettere informazioni aggiuntive rispettivamente su richieste e risposte. Ecco alcuni semplici esempi:

  • L'intestazione della richiesta di autorizzazione trasmette le credenziali utente al server:
    Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l
  • L'intestazione Content-Type indica il tipo di contenuti della richiesta/risposta inviati:
    Content-Type: application/json

Le intestazioni HTTP possono avere uno o più valori a seconda delle definizioni dei campi di intestazione. Un'intestazione con più valori avrà valori separati da virgole. Ecco alcuni esempi di intestazioni che contengono più valori:

  • Cache-Control: no-cache, no-store, must-revalidate
  • Accept: text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8
  • X-Forwarded-For: 10.125.5.30, 10.125.9.125

Apigee consente agli sviluppatori di accedere facilmente alle intestazioni utilizzando le variabili di flusso in uno qualsiasi dei criteri o dei flussi condizionali. Ecco l'elenco delle variabili che possono essere utilizzate per accedere a un'intestazione di richiesta o risposta specifica in Apigee:

Variabili di flusso:

  • message.header.header-name
  • request.header.header-name
  • response.header.header-name
  • message.header.header-name.N
  • request.header.header-name.N
  • response.header.header-name.N

Oggetti JavaScript:

  • context.proxyRequest.headers.header-name
  • context.targetRequest.headers.header-name
  • context.proxyResponse.headers.header-name
  • context.targetResponse.headers.header-name

Di seguito è riportato un esempio di criterio AssignMessage che mostra come leggere il valore di un'intestazione della richiesta e memorizzarlo in una variabile:

<AssignMessage continueOnError="false" enabled="true" name="assign-message-default">
  <AssignVariable>
    <Name>reqUserAgent</Name>
    <Ref>request.header.User-Agent</Ref>
  </AssignVariable>
</AssignMessage>

Antipattern

L'accesso ai valori delle intestazioni HTTP nelle norme Apigee in modo da restituire solo il primo valore è errato e può causare problemi se l'intestazione HTTP specifica ha più di un valore.

Le seguenti sezioni contengono esempi di accesso all'intestazione.

Esempio 1: leggere un'intestazione Accept con più valori utilizzando il codice JavaScript

Considera che l'intestazione Accept ha più valori, come mostrato di seguito:

Accept: text/html, application/xhtml+xml, application/xml

Ecco il codice JavaScript che legge il valore dall'intestazione Accept:

// Read the values from Accept header
var acceptHeaderValues = context.getVariable("request.header.Accept");

Il codice JavaScript riportato sopra restituisce solo il primo valore dell'intestazione Accept, ad esempio text/html.

Esempio 2: lettura di un'intestazione Access-Control-Allow-Headers con più valori nella policy AssignMessage o RaiseFault

Considera che l'intestazione Access-Control-Allow-Headers ha più valori, come mostrato di seguito:

Access-Control-Allow-Headers: content-type, authorization

Ecco la parte di codice dell'impostazione della policy AssignMessage o RaiseFault che imposta l'intestazione Access-Control-Allow-Headers:

<Set>
  <Headers>
    <Header name="Access-Control-Allow-Headers">{request.header.Access-Control-Request-Headers}</Header>
  </Headers>
</Set>

Il codice riportato sopra imposta l'intestazione Access-Control-Allow-Headers con solo il primo valore dell'intestazione della richiesta Access-Control-Allow-Headers, in questo esempio content-type.

Impatto

  1. In entrambi gli esempi precedenti, nota che viene restituito solo il primo valore delle intestazioni con più valori. Se questi valori vengono successivamente utilizzati da un altro criterio nel flusso del proxy API o dal servizio di backend per eseguire una funzione o una logica, potrebbero portare a un risultato imprevisto.
  2. Quando i valori delle intestazioni delle richieste vengono accessi e passati al server di destinazione, le richieste API potrebbero essere elaborate in modo errato dal backend e quindi potrebbero fornire risultati errati.
  3. Se l'applicazione client dipende da valori di intestazione specifici della risposta Apigee, potrebbe anche essere elaborata in modo errato e fornire risultati errati.

Best practice

  1. Fai riferimento al modulo request.header.header_name.values.string della variabile di flusso per leggere tutti i valori di un'intestazione specifica.

    Esempio: frammento di esempio che potrebbe essere utilizzato in RaiseFault o AssignMessage per leggere un'intestazione con più valori

    <Set>
      <Headers>
        <Header name="Inbound-Headers">{request.header.Accept.values.string}</Header>
      </Headers>
    </Set>
  2. Se vuoi accedere individualmente a ciascuno dei valori distinti, puoi utilizzare le variabili di flusso integrate appropriate: request.header.header_name.values.count, request.header.header_name.N, response.header.header_name.values.count, response.header.header_name.N.

    Poi esegui l'iterazione per recuperare tutti i valori di un'intestazione specifica nelle norme JavaScript o JavaCallout.

    Esempio: codice JavaScript di esempio per leggere un'intestazione con più valori

    for (var i = 1; i <=context.getVariable('request.header.Accept.values.count'); i++)
    {
      print(context.getVariable('request.header.Accept.' + i));
    }

    Ad esempio, application/xml;q=0.9, */*;q=0.8 verrà visualizzato come due valori con il codice riportato sopra. Il primo valore è application/xml;q=0.9 e il secondo sarà */*;q=0.8 .

    Se i valori dell'intestazione devono essere suddivisi utilizzando il punto e virgola come delimitatore, puoi utilizzare string.split(";") all'interno del callout JavaScript per separare i valori distinti.

  3. In alternativa, puoi utilizzare la funzione substring() disponibile in un modello di messaggio nella variabile di flusso request.header.header_name.values per leggere tutti i valori di un'intestazione specifica.

    Esempio: utilizza substring() all'interno di un modello di messaggio per leggere un'intestazione multivalore completa

    <Set>
      <Headers>
       <Header name="Inbound-Headers">{substring(request.header.Accept.values,1,-1)}</Header>
      </Headers>
    </Set>

Per approfondire