Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
SI APPLICA A: Tutti i livelli di Gestione API
Il servizio Gestione API di Azure include il supporto predefinito per la memorizzazione nella cache delle risposte HTTP usando l'URL della risorsa come chiave. È possibile modificare la chiave usando le intestazioni di richiesta che usano le vary-by proprietà . Questa tecnica è utile per memorizzare nella cache intere risposte HTTP (note anche come rappresentazioni), ma a volte è utile memorizzare nella cache solo una parte di una rappresentazione. I criteri cache-lookup-value e cache-store-value consentono di archiviare e recuperare dati arbitrari dall'interno delle definizioni dei criteri. Questa possibilità aggiunge anche valore ai criteri send-request perché è possibile memorizzare nella cache le risposte dai servizi esterni.
Architecture
Il servizio Gestione API usa una cache dei dati interna condivisa per tenant in modo che, man mano che si aumentano fino a più unità, si ottiene comunque l'accesso agli stessi dati memorizzati nella cache. Tuttavia, quando si lavora con una distribuzione in più aree sono presenti cache indipendenti all'interno di ognuna delle aree. È importante non considerare la cache come archivio dati, dove è l'unica origine di alcune informazioni. Se è stato fatto e successivamente si è deciso di sfruttare la distribuzione in più aree, i clienti con utenti che viaggiano potrebbero perdere l'accesso a tali dati memorizzati nella cache.
Annotazioni
La cache interna non è disponibile nel livello a consumo di Gestione API di Azure. È invece possibile usare una cache esterna compatibile con Redis . Una cache esterna consente un maggiore controllo della cache e flessibilità per le istanze di Gestione API in tutti i livelli.
Memorizzazione nella cache dei frammenti
Esistono alcuni casi in cui le risposte restituite contengono alcune parti di dati che sono costose da determinare. Tuttavia, i dati rimangono aggiornati per un periodo di tempo ragionevole. Si consideri, ad esempio, un servizio creato da una compagnia aerea che fornisce informazioni relative alle prenotazioni di voli, allo stato dei voli e così via. Se l'utente è membro del programma di punti delle compagnie aeree, avrà anche informazioni relative al loro stato attuale e al chilometraggio accumulato. Queste informazioni relative all'utente potrebbero essere archiviate in un sistema diverso, ma potrebbe essere preferibile includerlo nelle risposte restituite sullo stato del volo e sulle prenotazioni. È possibile includere questi dati usando un processo denominato memorizzazione nella cache dei frammenti. La rappresentazione primaria può essere restituita dal server di origine usando un tipo di token per indicare dove inserire le informazioni correlate all'utente.
Si consideri la risposta JSON seguente da un'API back-end.
{
"airline" : "Air Canada",
"flightno" : "871",
"status" : "ontime",
"gate" : "B40",
"terminal" : "2A",
"userprofile" : "$userprofile$"
}
E una risorsa secondaria in /userprofile/{userid} che presenta un aspetto simile,
{ "username" : "Bob Smith", "Status" : "Gold" }
Per determinare le informazioni utente appropriate da includere, Gestione API deve identificare chi è l'utente finale. Questo meccanismo dipende dall'implementazione. Nell'esempio seguente viene utilizzata la richiesta Subject di un token JWT.
<set-variable
name="enduserid"
value="@(context.Request.Headers.GetValueOrDefault("Authorization","").Split(' ')[1].AsJwt()?.Subject)" />
Gestione API archivia il enduserid valore in una variabile di contesto per un uso successivo. Il passaggio successivo consiste nel determinare se una richiesta precedente ha già recuperato le informazioni utente e la ha archiviata nella cache. A tale scopo, Gestione API usa i criteri cache-lookup-value.
<cache-lookup-value
key="@("userprofile-" + context.Variables["enduserid"])"
variable-name="userprofile" />
<rate-limit calls="10" renewal-period="60" />
Annotazioni
Aggiungi una policy di limite di velocità (o politica limite di velocità per chiave ) dopo la ricerca della cache per aiutare a limitare il numero di chiamate e prevenire sovraccarichi sul servizio backend nel caso in cui la cache non sia disponibile.
Se nella cache non è presente alcuna voce corrispondente al valore della chiave, non viene creata alcuna userprofile variabile di contesto. La gestione delle API verifica il successo della ricerca usando i criteri di flusso di controllo choose.
<choose>
<when condition="@(!context.Variables.ContainsKey("userprofile"))">
<!-- If the userprofile context variable doesn’t exist, make an HTTP request to retrieve it. -->
</when>
</choose>
Se la userprofile variabile di contesto non esiste, Gestione API dovrà effettuare una richiesta HTTP per recuperarla.
<send-request
mode="new"
response-variable-name="userprofileresponse"
timeout="10"
ignore-error="true">
<!-- Build a URL that points to the profile for the current end-user -->
<set-url>@(new Uri(new Uri("https://apimairlineapi.azurewebsites.net/UserProfile/"),
(string)context.Variables["enduserid"]).AbsoluteUri)
</set-url>
<set-method>GET</set-method>
</send-request>
Per creare l'URL per la risorsa del profilo utente, Gestione API usa enduserid. Quando API Management riceve la risposta, estrae il testo del corpo dalla risposta e lo archivia in una variabile di contesto.
<set-variable
name="userprofile"
value="@(((IResponse)context.Variables["userprofileresponse"]).Body.As<string>())" />
Per evitare che Gestione API effettui nuovamente questa richiesta HTTP quando lo stesso utente effettua un'altra richiesta, è possibile specificare che il profilo utente viene archiviato nella cache.
<cache-store-value
key="@("userprofile-" + context.Variables["enduserid"])"
value="@((string)context.Variables["userprofile"])" duration="100000" />
Gestione API archivia il valore nella cache usando la stessa chiave con cui Gestione API ha tentato originariamente di recuperarlo. La durata per cui API Management sceglie di archiviare il valore dovrebbe essere basata su quanto spesso cambiano le informazioni e su quanto gli utenti siano tolleranti rispetto a informazioni non aggiornate.
È importante rendersi conto che il recupero di informazioni dalla cache è ancora una richiesta di rete out-of-process e può potenzialmente aggiungere decine di millisecondi alla richiesta. I vantaggi si presentano quando la determinazione delle informazioni sul profilo utente richiede più tempo rispetto al recupero delle informazioni dalla cache, a causa della necessità di eseguire query di database o aggregare informazioni da più back-end.
Il passaggio finale del processo consiste nell'aggiornare la risposta restituita con le informazioni sul profilo utente.
<!-- Update response body with user profile-->
<find-and-replace
from='"$userprofile$"'
to="@((string)context.Variables["userprofile"])" />
È possibile scegliere di includere le virgolette come parte del token in modo che, anche quando la sostituzione non si verifica, la risposta è ancora json valida.
Dopo aver combinato questi passaggi, il risultato finale è un criterio simile al seguente.
<policies>
<inbound>
<!-- How you determine user identity is application dependent -->
<set-variable
name="enduserid"
value="@(context.Request.Headers.GetValueOrDefault("Authorization","").Split(' ')[1].AsJwt()?.Subject)" />
<!--Look for userprofile for this user in the cache -->
<cache-lookup-value
key="@("userprofile-" + context.Variables["enduserid"])"
variable-name="userprofile" />
<rate-limit calls="10" renewal-period="60" />
<!-- If API Management doesn’t find it in the cache, make a request for it and store it -->
<choose>
<when condition="@(!context.Variables.ContainsKey("userprofile"))">
<!-- Make HTTP request to get user profile -->
<send-request
mode="new"
response-variable-name="userprofileresponse"
timeout="10"
ignore-error="true">
<!-- Build a URL that points to the profile for the current end-user -->
<set-url>@(new Uri(new Uri("https://apimairlineapi.azurewebsites.net/UserProfile/"),(string)context.Variables["enduserid"]).AbsoluteUri)</set-url>
<set-method>GET</set-method>
</send-request>
<!-- Store response body in context variable -->
<set-variable
name="userprofile"
value="@(((IResponse)context.Variables["userprofileresponse"]).Body.As<string>())" />
<!-- Store result in cache -->
<cache-store-value
key="@("userprofile-" + context.Variables["enduserid"])"
value="@((string)context.Variables["userprofile"])"
duration="100000" />
</when>
</choose>
<base />
</inbound>
<outbound>
<!-- Update response body with user profile-->
<find-and-replace
from='"$userprofile$"'
to="@((string)context.Variables["userprofile"])" />
<base />
</outbound>
</policies>
Questo approccio alla memorizzazione nella cache viene usato principalmente nei siti Web in cui HTML è composto sul lato server in modo che possa essere eseguito il rendering come singola pagina. Può anche essere utile nelle API in cui i client non possono eseguire la memorizzazione nella cache HTTP sul lato client o è consigliabile non mettere tale responsabilità sul client.
Questo stesso tipo di memorizzazione nella cache dei frammenti può essere eseguito anche nei server Web back-end usando un server di memorizzazione nella cache Redis. Tuttavia, l'uso del servizio Gestione API per eseguire questo lavoro è utile quando i frammenti memorizzati nella cache provengono da back-end diversi rispetto alle risposte primarie.
Versionamento trasparente
È pratica comune che più versioni di implementazione diverse di un'API siano supportate in qualsiasi momento. Ad esempio, per supportare ambienti diversi (sviluppo, test, produzione e così via) o per supportare le versioni precedenti dell'API per consentire ai consumer di API di eseguire la migrazione a versioni più recenti.
Un approccio alla gestione di più versioni, invece di richiedere agli sviluppatori client di modificare gli URL da /v1/customers a /v2/customers, consiste nell'archiviare nei dati del profilo del consumer la versione dell'API da usare e chiamare l'URL back-end appropriato. Per determinare l'URL back-end corretto da chiamare per un determinato client, è necessario eseguire query su alcuni dati di configurazione. Quando si memorizzano nella cache questi dati di configurazione, Gestione API può ridurre al minimo l'impatto sulle prestazioni di questa ricerca.
Il primo passaggio consiste nel determinare l'identificatore usato per configurare la versione desiderata. In questo esempio la versione viene associata al codice Product Subscription Key.
<set-variable name="clientid" value="@(context.Subscription.Key)" />
Gestione API esegue quindi una ricerca nella cache per verificare se è già stata recuperata la versione client desiderata.
<cache-lookup-value
key="@("clientversion-" + context.Variables["clientid"])"
variable-name="clientversion" />
<rate-limit calls="10" renewal-period="60" />
Annotazioni
Aggiungi una policy di limite di velocità (o politica limite di velocità per chiave ) dopo la ricerca della cache per aiutare a limitare il numero di chiamate e prevenire sovraccarichi sul servizio backend nel caso in cui la cache non sia disponibile.
Gestione API verifica quindi se non lo trova nella cache.
<choose>
<when condition="@(!context.Variables.ContainsKey("clientversion"))">
Se Gestione API non lo ha trovato, Gestione API lo recupera.
<send-request
mode="new"
response-variable-name="clientconfiguresponse"
timeout="10"
ignore-error="true">
<set-url>@(new Uri(new Uri(context.Api.ServiceUrl.ToString() + "api/ClientConfig/"),(string)context.Variables["clientid"]).AbsoluteUri)</set-url>
<set-method>GET</set-method>
</send-request>
Estrarre il corpo della risposta dalla risposta.
<set-variable
name="clientversion"
value="@(((IResponse)context.Variables["clientconfiguresponse"]).Body.As<string>())" />
Archiviarlo nuovamente nella cache per un uso futuro.
<cache-store-value
key="@("clientversion-" + context.Variables["clientid"])"
value="@((string)context.Variables["clientversion"])"
duration="100000" />
Aggiornare infine l'URL back-end per selezionare la versione del servizio desiderata dal client.
<set-backend-service
base-url="@(context.Api.ServiceUrl.ToString() + "api/" + (string)context.Variables["clientversion"] + "/")" />
Il criterio completo è il seguente:
<inbound>
<base />
<set-variable name="clientid" value="@(context.Subscription.Key)" />
<cache-lookup-value key="@("clientversion-" + context.Variables["clientid"])" variable-name="clientversion" />
<rate-limit calls="10" renewal-period="60" />
<!-- If API Management doesn’t find it in the cache, make a request for it and store it -->
<choose>
<when condition="@(!context.Variables.ContainsKey("clientversion"))">
<send-request mode="new" response-variable-name="clientconfiguresponse" timeout="10" ignore-error="true">
<set-url>@(new Uri(new Uri(context.Api.ServiceUrl.ToString() + "api/ClientConfig/"),(string)context.Variables["clientid"]).AbsoluteUri)</set-url>
<set-method>GET</set-method>
</send-request>
<!-- Store response body in context variable -->
<set-variable name="clientversion" value="@(((IResponse)context.Variables["clientconfiguresponse"]).Body.As<string>())" />
<!-- Store result in cache -->
<cache-store-value key="@("clientversion-" + context.Variables["clientid"])" value="@((string)context.Variables["clientversion"])" duration="100000" />
</when>
</choose>
<set-backend-service base-url="@(context.Api.ServiceUrl.ToString() + "api/" + (string)context.Variables["clientversion"] + "/")" />
</inbound>
Questa soluzione elegante risolve molti problemi di controllo delle versioni delle API, consentendo ai consumer di API di controllare in modo trasparente la versione back-end a cui accedono i client senza dover aggiornare e ridistribuire i client.
Isolamento dei tenant
In implementazioni più grandi e multi-tenant alcune aziende creano gruppi separati di tenant su distribuzioni distinte dell'hardware di backend. Questa struttura riduce al minimo il numero di clienti interessati quando si verificano problemi hardware nel back-end. Consente inoltre di implementare nuove versioni software in fasi. Idealmente questa architettura back-end deve essere trasparente per i consumer di API. È possibile ottenere questa trasparenza usando una tecnica simile al controllo delle versioni trasparente, modificando l'URL back-end usando lo stato di configurazione per ogni chiave API.
Anziché restituire una versione preferita dell'API per ogni chiave di sottoscrizione, si restituirà un identificatore che correla un tenant al gruppo hardware assegnato. Tale identificatore può essere usato per costruire l'URL back-end appropriato.
Riassunto
La libertà di usare la cache di Gestione API di Azure per l'archiviazione di qualsiasi tipo di dati consente un accesso efficiente ai dati di configurazione che possono influire sulla modalità di elaborazione di una richiesta in ingresso. Può anche essere usato per archiviare frammenti di dati che possono aumentare le risposte, restituite da un'API back-end.