# Idempotenza e rate limiting: chiavi, 429, Retry-After, RateLimit

> L'header Idempotency-Key (draft IETF) rende sicuro un POST ritentato: il server memorizza il primo risultato per chiave entro una finestra di dedup e lo riproduce per ogni ripetizione, offrendo una submission exactly-once. Il rate limiting protegge il servizio: le richieste oltre il limite ricevono 429 Too Many Requests con Retry-After, e gli header RateLimit pubblicizzano la quota residua così che i client si auto-limitino.

- URL canonico: https://www.broadnet.me/it/reference/idempotency-and-rate-limiting
- Lingua: it
- Ultimo aggiornamento: 2026-07-19
- Editore: BroadNet (https://www.broadnet.me)

Due pattern HTTP standards-track per client sicuri e ben educati: l'header Idempotency-Key (draft IETF) per una submission exactly-once con finestra di dedup e replay della risposta, e il rate limiting — 429 con Retry-After, gli header RateLimit / RateLimit-Policy (draft IETF), i token bucket e la backpressure lato client.

## L'header Idempotency-Key

La submission di un messaggio è un POST, che non è idempotente, eppure le reti costringono i client a ritentare quando una risposta va persa — creando il classico doppio invio. Il draft Idempotency-Key del gruppo di lavoro HTTP-API dell'IETF standardizza la soluzione: il client genera una chiave univoca (una UUID) per operazione logica e la invia nell'header di richiesta Idempotency-Key. Il server registra la chiave con l'esito della prima richiesta e, se vede di nuovo la stessa chiave, non esegue una seconda volta — restituisce il risultato memorizzato. Così un retry dopo un timeout è garantito innocuo: o il primo tentativo non è mai arrivato (e questo esegue) oppure sì (e il suo risultato viene riprodotto). La chiave appartiene all'operazione, non alla connessione, quindi il client riutilizza la stessa chiave su ogni retry di quel singolo invio.

*POST idempotente con una chiave generata dal client*

```http
# Generic IETF-draft example (not the BroadNet API, which takes no
# Idempotency-Key header: see /developers/idempotency)
POST /v1/messages HTTP/1.1
Host: api.example
Idempotency-Key: 8f14e45f-ea7b-4c0f-9b2a-1d2c3e4f5a6b
Content-Type: application/json

{ "to": "+15551234567", "text": "..." }

# first call  -> 202 Accepted, id 01HZY8Q3M6   (executed, stored)
# same key    -> 202 Accepted, id 01HZY8Q3M6   (replayed, not re-sent)
```

## Finestra di dedup, replay della risposta e conflitti

Una idempotency key non viene ricordata per sempre; il server la conserva per una finestra di dedup (comunemente 24 ore) abbastanza a lungo da coprire qualsiasi retry realistico, poi la fa scadere. Entro quella finestra una ripetizione della chiave riproduce lo status code e il body memorizzati verbatim — lo stesso 202 e lo stesso id di messaggio — così che il client veda esattamente ciò che avrebbe visto se fosse arrivata la prima risposta. Due casi limite richiedono una gestione esplicita. Se una chiave viene riutilizzata con un body di richiesta diverso, si tratta di un bug del client e il server restituisce 409 Conflict invece di inviare silenziosamente la cosa sbagliata. Se un retry arriva mentre la prima richiesta è ancora in volo, il server restituisce un conflitto o 'in progress' invece di avviare una seconda esecuzione, così che la concorrenza non possa sconfiggere la garanzia.

*Esiti dell'Idempotency-Key*

| Situazione | Comportamento del server | Stato |
|---|---|---|
| Nuova chiave | Esegui, memorizza chiave + risultato | Normale (es. 202) |
| Stessa chiave, stesso corpo | Riproduci la risposta memorizzata, non rieseguirla | Stato originale |
| Stessa chiave, corpo diverso | Rifiuta — chiave associata al primo payload | 409 Conflict |
| Ripetizione mentre la prima richiesta è ancora in corso | Non avviare una seconda esecuzione | 409 / in corso |
| Chiave scaduta (oltre la finestra) | Trattato come nuovo | Normale |

## Rate limiting e 429

Una piattaforma di messaggistica condivisa protegge se stessa e gli altri tenant limitando la velocità con cui qualsiasi client può chiamare, e segnala una violazione con uno status specifico. RFC 9110 e RFC 6585 definiscono 429 Too Many Requests proprio per questo: il client ha inviato troppe richieste in un dato tempo. Un server ben educato accompagna il 429 con un header Retry-After che indica al client quanto attendere prima di riprovare (un ritardo in secondi o una data HTTP). L'obbligo del client è rispettarlo — fermarsi, attendere l'intervallo indicato, poi riprendere — anziché ritentare immediatamente, cosa che non fa che aggravare il sovraccarico. Un 429 è transitorio e sicuro da ritentare, a differenza di un 4xx che indica una richiesta malformata.

*429 con gli header Retry-After e RateLimit*

```http
HTTP/1.1 429 Too Many Requests
Retry-After: 2
RateLimit: limit=100, remaining=0, reset=2
RateLimit-Policy: 100;w=1
Content-Type: application/problem+json

{ "type": "https://example/problems/rate-limited",
  "title": "Too Many Requests", "status": 429 }
```

## Gli header RateLimit e RateLimit-Policy

Reagire a un 429 a cose fatte è dispendioso; il draft RateLimit-headers dell'IETF consente a un client di vedere il proprio budget prima di superarlo. Sulle risposte ordinarie il server pubblicizza la quota corrente con un header RateLimit che porta il limite, l'allowance residua e i secondi al reset della finestra, e un header RateLimit-Policy che descrive la policy stessa (per esempio 100 richieste per finestra di 1 secondo). Un client che li legge può regolare il proprio passo — rallentando man mano che remaining si avvicina a zero — e non innescare affatto un 429. Questo trasforma il rate limiting da un rifiuto punitivo a posteriori in un segnale cooperativo, che è l'intero scopo di standardizzare i nomi degli header così che qualsiasi client library possa consumarli.

*Header standard di segnalazione del rate limit*

| Header | Trasporta | Esempio |
|---|---|---|
| 429 Too Many Requests | Lo stato di superamento del limite | riga di stato |
| Retry-After | Quanto tempo aspettare prima di riprovare | Retry-After: 2 |
| RateLimit | limite / rimanenti / reset per la finestra | limit=100, remaining=17, reset=1 |
| RateLimit-Policy | La policy di quota in vigore | 100;w=1 (100 per 1s) |

## Token bucket e come si applicano i limiti

L'algoritmo token bucket è il meccanismo consueto dietro questi header perché limita il rate sostenuto tollerando brevi burst. Un bucket contiene fino a un numero fisso di token e si ricarica a rate costante; ogni richiesta rimuove un token, e una richiesta che trova il bucket vuoto viene rifiutata con 429. La dimensione del bucket fissa il burst che un client può spendere in una volta e il rate di ricarica fissa il tetto di lungo periodo, così un client può inviare un burst rapido dopo un periodo di inattività ma non può superare la media. Il valore remaining di RateLimit è di fatto il conteggio dei token, e reset è quando il bucket sarà ricaricato — che è esattamente l'informazione che serve a un client cadenzato. Questo flow control a livello HTTP è l'analogo REST del window sizing SMPP e del throttling di enquire_link sulla sessione binaria.

## Backpressure lato client

La metà lato client del buon comportamento di rate limit è la backpressure: modellare il carico in uscita così che resti entro il budget pubblicizzato invece di sparare tutto e assorbire i 429. In pratica ciò significa un limiter lato client (un token bucket che rispecchia quello del server), la lettura degli header RateLimit per regolare il passo e, su un 429, un backoff per l'intervallo Retry-After con jitter prima di riprendere. Per un invio massivo ciò significa dosare le submission fino al tetto sostenuto anziché scaricarle tutte, così che la piattaforma resti sana e la latenza del client stesso resti prevedibile. BroadNet documenta il suo comportamento concreto di idempotenza e rate limit per gli sviluppatori.

## Domande frequenti

### Cosa fa l'header Idempotency-Key?

Rende sicuro un POST ritentato. Il client invia una chiave univoca per operazione logica; il server esegue la prima richiesta con quella chiave e ne memorizza il risultato, poi riproduce il risultato memorizzato per ogni ripetizione della stessa chiave entro una finestra di dedup. Così un retry dopo una risposta persa o esegue una volta o riproduce — mai un doppio invio. È specificato in un draft del gruppo di lavoro HTTP-API dell'IETF.

### Per quanto tempo il server ricorda una idempotency key?

Per una finestra di dedup — comunemente intorno alle 24 ore — abbastanza a lungo da coprire qualsiasi retry realistico, dopo la quale la chiave scade e un riutilizzo è trattato come nuovo. Entro la finestra, una ripetizione della chiave riproduce lo status code e il body originali verbatim invece di rieseguire.

### Cosa succede se riutilizzo una idempotency key con un body diverso?

Il server la rifiuta con 409 Conflict. La chiave è legata al payload della prima richiesta, quindi riutilizzarla con un body diverso è trattato come un errore del client anziché inviare silenziosamente il messaggio sbagliato. Riutilizza la stessa chiave solo per i retry dell'operazione identica.

### Cosa dovrebbe fare un client quando riceve un 429?

Fermarsi e rispettare l'header Retry-After — attendere i secondi indicati (o fino alla data data), poi riprendere — anziché ritentare immediatamente, cosa che non fa che aggravare il sovraccarico. Un 429 è transitorio e sicuro da ritentare una volta trascorsa l'attesa, idealmente con un po' di jitter così che molti client non riprendano all'unisono.

### A cosa servono gli header RateLimit e RateLimit-Policy?

Consentono a un client di vedere la propria quota prima di superarla. RateLimit porta il limite, l'allowance residua e il tempo di reset per la finestra corrente; RateLimit-Policy descrive la policy (per esempio 100 richieste al secondo). Un client che li legge può regolare il proprio passo ed evitare del tutto di innescare un 429. Entrambi sono definiti in un draft IETF.

### Come si collega un token bucket agli header RateLimit?

Il token bucket è il meccanismo di applicazione: un bucket di dimensione fissa si ricarica a rate costante, ogni richiesta spende un token e un bucket vuoto produce un 429. Il valore remaining di RateLimit è essenzialmente il conteggio corrente dei token e reset è quando il bucket si ricarica — così un client che legge quegli header sa esattamente quanto burst e rate sostenuto gli restano.

## Fonti

- [IETF draft — Idempotency-Key HTTP Header Field](https://datatracker.ietf.org/doc/html/draft-ietf-httpapi-idempotency-key-header)
- [IETF draft — RateLimit header fields for HTTP](https://datatracker.ietf.org/doc/html/draft-ietf-httpapi-ratelimit-headers)

## Correlati

- [Progettazione di API di messaggistica REST](https://www.broadnet.me/it/reference/rest-messaging-api-design)
- [Consegna e affidabilità dei webhook](https://www.broadnet.me/it/reference/webhook-delivery-and-reliability)
- [SMPP enquire_link e throttling](https://www.broadnet.me/it/reference/smpp-enquire-link-throttling)
- [Guida all'idempotenza di BroadNet](https://www.broadnet.me/developers/idempotency)
- [Rate limit di BroadNet](https://www.broadnet.me/it/developers/rate-limits)
