Limitare il numero di richieste ad ASP.NET Web API

di Moreno Gentili, in ASP.NET Web API,

Sempre più spesso, sviluppare un qualsiasi tipo di applicazione web o Windows significa anche attingere dati da servizi remoti, consumabili comodamente attraverso una API accessibile via web. Questa pratica è diventata così comune che ha suggerito la creazione di marketplace specifici.
Una Web API che offra dati rilevanti per il pubblico, quindi, può facilmente diventare un mattone fondamentale per il successo di applicazioni sviluppate da terze parti.

Uno dei passi da affrontare per rendere profittevole la nostra Web API, consiste nell'identificare dei livelli di servizio che, a tariffe via via crescenti, soddisfino le esigenze di budget di chi ha bisogno di farne un uso saltuario da chi invece ne vuol fare un uso massivo.

Il pacchetto WebApiThrottle ci aiuta nel limitare la frequenza con cui ogni client può rivolgere richieste alla nostra applicazione ASP.NET Web API.
Porre dei limiti non è solo un meccanismo di protezione contro l'aumento indiscriminato di richieste, ma è anche un modo per ottimizzare le risorse e garantire una capacità più elevata a coloro che hanno acquistato un livello di servizio superiore (ed incentivare gli altri a fare altrettanto).

Il pacchetto permette di distinguere i client secondo una qualsiasi combinazione dei seguenti criteri:

  • la API Key fornita;
  • l'indirizzo IP di provenienza;
  • l'URL della action alla quale è rivolta la richiesta.

In questo esempio esploreremo il primo criterio, ovvero limiteremo le richieste dei client in base alla API Key che abbiamo rilasciato loro.

Iniziamo digitando quanto segue dalla Package Manager Console di Visual Studio 2015:

Install-Package WebApiThrottle

Ora apriamo il file /App_Start/WebApiConfig.cs e nel suo metodo Register aggiungiamo ai MessageHandlers un'istanza di ThrottlingHandler così configurata:

// Il ThrottlingHandler si occuperà di bloccare le richieste troppo frequenti,
// prima ancora che vengano elaborate dalle action della nostra Web API
config.MessageHandlers.Add(new ThrottlingHandler()
{
  // Questi sono i limiti di default per i client che non forniscono una API key.
  // Possiamo indicare un numero di richieste al secondo, al minuto, 
  // all'ora, al giorno e/o alla settimana
  Policy = new ThrottlePolicy(perSecond: 1, perMinute: 30, perHour: 100)
  {
    // Abilitiamo la limitazione dei clienti sulla base delle loro API Key
    ClientThrottling = true,
  
    // Indichiamo delle limitazioni meno restrittive
    // per queste due specifiche API Key
    ClientRules = new Dictionary<string, RateLimits>
    {
      { "APIKeyClient1", new RateLimits 
        { 
          PerSecond = 2, PerMinute = 100, PerHour = 1000
        } 
      },
      { "APIKeyClient2", new RateLimits
         { 
           PerSecond = 2, PerMinute = 200, PerHour = 5000 
         } 
      },
    }
  },
  // I contatori di utilizzo della Web API (anche chiamati "metriche")
  // verranno mantenuti in cache
  Repository = new CacheRepository(),
  
  // Facoltativo: manteniamo uno storico delle richieste bloccate. 
  // Per questo usiamo il tracing di ASP.Net Web API
  // Per attivarlo, si veda: 
  // https://www.aspitalia.com/script/1198/Attivare-Tracing-ASP.NET-Web-API.aspx
  Logger = new TracingThrottleLogger(config.EnableSystemDiagnosticsTracing())
});

A questo punto, la nostra applicazione ASP.NET Web API è già in grado di regolare il volume di richieste in ingresso e di limitare quei client che ne stanno inviando in numero eccessivo.
I client che intendono consumare la nostra Web API, forniranno la propria API Key con l'intestazione Authorization-Token della richiesta, come si vede in questo esempio:

GET http://www.example.com/api/CambioValute HTTP/1.1
Host: www.example.com
Accept: application/json
Authorization-Token: APIKeyClient1

All'arrivo di ogni richiesta, il ThrottlingHandler aggiornerà le proprie metriche, ovvero un insieme di contatori conservati nell'oggetto Cache (o MemoryCache) di ASP.NET che tracciano l'attività dei client nel tempo. Tali metriche possono anche essere preservate dopo un riavvio dell'applicazione se forniamo un diverso meccanismo di persistenza che implementi IThrottleRepository.

Fintanto che il client invia richieste con una frequenza rispettosa dei limiti configurati, allora otterrà normali risposte dall'applicazione. Se, al contrario, dovesse superare tali limiti, allora il ThrottlingHandler inizierà a bloccare le richieste e risponderà immediatamente con un output simile al seguente:

HTTP/1.1 429
Content-Type: application/json; charset=utf-8
Retry-After: 9
Date: Sat, 03 Oct 2015 11:05:55 GMT
Content-Length: 61

"API calls quota exceeded! maximum admitted 100 per Minute."

In questo esempio, il client viene informato del blocco con il codice di errore HTTP 429 (Too Many Requests) e con un messaggio che gli ricorda la limitazione da rispettare.
E' anche importante notare come l'intestazione Retry-After suggerisca il numero di secondi da attendere prima che la Web API sia di nuovo disponibile a fornire risposte.
Ovviamente nulla vieta ad un client di continuare ad inviare richieste che verranno bloccate ma, con la proprietà StackBlockedRequests della ThrottlePolicy, possiamo dissuadere questo comportamento. Grazie ad essa, infatti, anche le richieste bloccate andranno ad influire sulle metriche e perciò ad allungare ulteriormente il tempo di attesa.

Ogni richiesta bloccata può essere tracciata grazie al sistema di Tracing di ASP.NET Web API, così da monitorare l'attività dei client. A tal proposito, associamo un'implementazione di IThrottleLogger alla proprietà Logger della ThrottlePolicy ed otterremo righe di log come la seguente:

10/03/2015 08:39:19 
Request 4ED76E1F9FC5BE33062309158154A2FC8CAEDB88 
from 172.16.23.45 has been throttled (blocked), 
quota 10/Minute exceeded by 1

Il pacchetto WebApiThrottle offre molte altre possibilità di configurazione e vari punti di estendibilità. Per scenari d'uso avanzati, che prevedano il whitelisting di alcuni client o limitazioni applicate puntualmente sulle singole action, l'autore Stefan Prodan offre un'approfondita documentazione nel suo repository GitHub: [url]https://github.com/stefanprodan/WebApiThrottle[/url]

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

I più letti di oggi