Per costruire un URL shortener hai bisogno di quattro cose: un posto dove memorizzare la mappatura da un codice breve a un URL di destinazione, un modo per generare un codice univoco per ogni nuovo link, un handler di redirect che cerca il codice e restituisce un redirect HTTP, e una cache davanti alla ricerca perché le letture superano di gran lunga le scritture. Questo è l'intero nucleo, e puoi metterlo in piedi in un pomeriggio.
La trappola è pensare che la versione del pomeriggio sia il prodotto. Un redirect che funziona sul tuo laptop e un servizio di URL shortening che sopravvive agli estranei che lo puntano verso malware, lo martellano con il traffico, e si aspettano quattro nove di uptime sono problemi ingegneristici diversi. Il primo è un algoritmo. Il secondo è un impegno operativo.
Questa guida costruisce il nucleo in modo onesto, poi dedica la maggior parte del suo tempo alla parte che i tutorial di system design saltano: cosa devi ancora costruire dopo che il redirect funziona. Se vuoi prima il primer concettuale, come funzionano gli URL shortener copre i meccanismi senza il codice.
La versione breve: cosa fa davvero un URL shortener#
Un URL shortener è una ricerca chiave-valore che indossa un redirect HTTP. La chiave è il codice breve, il valore è l'URL lungo, e l'intero compito è trasformare example.com/aB3x9 in un 302 che punta all'indirizzo originale.
Il modello di dati è una tabella:
CREATE TABLE links (
id BIGSERIAL PRIMARY KEY,
short_code TEXT NOT NULL UNIQUE,
long_url TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE UNIQUE INDEX idx_links_short_code ON links (short_code);
Ci sono due percorsi attraverso di essa. Il percorso di scrittura prende un URL lungo, genera un codice breve e inserisce la riga. Il percorso di lettura prende un codice breve, cerca la riga e restituisce un redirect. Le letture dominano con un rapporto che è comunemente intorno a 1000 a 1, quindi quasi tutta la tua attenzione ingegneristica appartiene a rendere la ricerca veloce ed economica. L'indice univoco su short_code è ciò che mantiene quella ricerca una ricerca per indice invece di una scansione. Questo è l'intero nucleo.
Generare il codice breve: base62, casuale, o hash#
Il codice breve è dove si trova la decisione interessante. Hai tre strategie realistiche, e si scambiano lunghezza, prevedibilità, e quanto sono difficili le collisioni da gestire.
Base62 di un ID univoco è la soluzione classica. Prendi l'ID di riga auto-incrementante e codificalo in base62, i 62 caratteri a-z, A-Z, e 0-9. I codici sono brevi, non vanno mai in collisione perché ogni ID è univoco, e crescono di un carattere di lunghezza all'incirca ogni 62x in volume. Il lato negativo è che sono sequenziali e indovinabili, quindi chiunque può esplorare il tuo namespace.
const alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
// encode turns a positive integer ID into a base62 short code.
func encode(id uint64) string {
if id == 0 {
return string(alphabet[0])
}
var b []byte
for id > 0 {
b = append(b, alphabet[id%62])
id /= 62
}
// reverse, since we built the digits least-significant first
for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
b[i], b[j] = b[j], b[i]
}
return string(b)
}
Le stringhe casuali risolvono il problema della prevedibilità. Genera un codice casuale breve, ad esempio con una libreria come nanoid, e verificalo contro l'indice univoco prima di salvarlo. Con sette caratteri di base62 hai migliaia di miliardi di possibilità, quindi le collisioni sono rare, ma devi comunque gestire il raro inserimento che fallisce il vincolo di unicità riprovando con un nuovo codice.
L'hashing dell'URL è la terza opzione e di solito la peggiore. Un hash dell'URL lungo è deterministico, il che sembra conveniente, ma devi comunque troncarlo, ottieni comunque collisioni, e URL identici si mappano a codici identici, il che rivela informazioni. La maggior parte dei servizi di produzione sceglie base62 per gli ID interni o codici casuali per quelli pubblici. Gli slug personalizzati o brandizzati, i codici che un utente digita a mano, vengono validati contro lo stesso indice univoco prima di essere accettati.
Il percorso di redirect: 301 vs 302 e perché decide le tue analisi#
Il codice di stato del redirect non è una scelta estetica. Decide se vedrai mai un secondo clic.
Un 301 Moved Permanently dice ai browser e ai proxy che lo spostamento è permanente, quindi lo memorizzano nella cache. Dopo la prima visita, il browser può inviare i clic futuri direttamente alla destinazione senza toccare il tuo server. Ottimo per la velocità grezza, fatale per le analisi, perché i clic che vuoi più contare sono quelli che non ti raggiungono mai. La semantica HTTP è descritta in RFC 9110, che definisce sia i redirect permanenti che quelli temporanei.
Un 302 Found o 307 Temporary Redirect viene ri-richiesto ogni volta. Il browser interroga il tuo server ad ogni clic, il che significa che puoi contare ogni visita e puoi cambiare la destinazione in seguito senza dover combattere con le cache obsolete. Per un link shortener il cui intero valore è costituito da link modificabili e dati sui clic, questo è il valore predefinito corretto. Il costo è un round-trip di rete per clic, che un cache hit rende trascurabile.
La regola empirica: usa 302 a meno che tu non abbia un motivo specifico per voler il link bloccato e memorizzato nella cache per sempre. Il post redirect 301 vs 302 analizza il compromesso in dettaglio, e tipi di redirect copre il resto della famiglia 3xx, incluso quando 307 e 308 sono rilevanti.
Storage e caching: progettare per un rapporto lettura/scrittura di 1000:1#
Poiché le letture sommergono le scritture, il database non è il tuo collo di bottiglia, ma la tua strategia di cache lo è. Il pattern è una cache read-through: a un clic, controlla prima una cache in memoria, e torna al database solo in caso di miss, scrivendo il risultato nella cache per la prossima volta.
func resolve(ctx context.Context, code string) (string, error) {
if url, ok := cache.Get(code); ok {
return url, nil // hot path: served from memory
}
url, err := db.LookupLongURL(ctx, code)
if err != nil {
return "", err
}
cache.Set(code, url) // populate for the next click
return url, nil
}
In produzione questo di solito diventa due livelli: una piccola cache in-process per i link più caldi, supportata da un archivio in memoria condiviso come Redis in modo che ogni istanza del server benefici di una ricerca già effettuata da una qualsiasi di esse. Il database, la fonte di verità, viene toccato solo in caso di un genuino cold miss. Azzecca questo livello e un singolo server modesto gestisce un enorme volume di clic. Il post strategia di cache per i redirect URL approfondisce le decisioni di eviction e dimensionamento, e il riferimento principale su raggiungere p95 sotto 15ms mostra come appare un percorso di redirect ottimizzato sotto carico.
Se preferisci non gestire nulla di tutto ciò, l'API di Elido ti fornisce il livello di redirect, la cache, e la consegna EU in-region con p95 sotto 15ms su un cache hit, dietro una singola chiamata. Inizia gratis e salta le operazioni.
Contare i clic senza rallentare il redirect#
L'errore che uccide la latenza del redirect è scrivere il clic nel database all'interno dell'handler di redirect. Fai così e ogni visitatore aspetta che la tua scrittura di analisi completi prima di ottenere il suo redirect.
Disaccoppiali. L'handler emette il redirect immediatamente, poi lancia l'evento clic in un log durevole o in una coda di messaggi come lavoro fire-and-forget. Un consumer separato legge quel flusso e scrive gli eventi in un archivio di analisi secondo il proprio programma. Il visitatore non aspetta mai, e una query di reportistica che scansiona milioni di righe di clic non compete mai con il percorso di redirect per le risorse. Un database di analisi colonnare gestisce quelle query aggregate molto meglio di un row store, motivo per cui gli eventi clic di solito finiscono in un posto diverso dalla tabella dei link. Il post click ingestion fire-and-forget dettaglia il lato della coda, e perché un archivio colonnare batte Postgres per le analisi dei clic spiega la scelta di storage. Le analisi di Elido seguono questa forma affinché i clic siano interrogabili in secondi senza aggiungere millisecondi al redirect.
Cosa devi ancora costruire: l'80% difficile#
Ecco la parte che le guide di system design lasciano fuori. Un redirect funzionante è forse un quinto di un vero servizio di URL shortening. Il resto è tutto ciò che trasforma una demo in qualcosa che puoi mettere su internet pubblico.
- Scansione degli abusi e della sicurezza. Un shortener pubblico diventa un magnete per il phishing entro ore dal lancio. Devi controllare le destinazioni contro un feed di minacce come Google Safe Browsing e ri-scansionare, perché un URL pulito alla creazione può diventare malevolo in seguito. La checklist di sicurezza per URL shortener è l'elenco completo.
- Limitazione della frequenza e idempotenza. Un endpoint di creazione aperto viene scriptato istantaneamente. Hai bisogno di limiti per chiave e idempotenza in modo che una richiesta ripetuta non crei link duplicati. I meccanismi sono in limiti di frequenza API e idempotenza.
- Domini personalizzati con TLS. I link brandizzati significano emettere certificati per domini che non possiedi, su richiesta, senza passaggi manuali.
- Dati sui clic conformi al GDPR. Dal momento in cui registri i clic stai elaborando dati personali. Troncare gli indirizzi IP e documentare la retention non è opzionale nell'UE, come spiega GDPR per gli URL shortener.
- Alta disponibilità. Il tuo redirect è ora sul percorso critico di ogni link che chiunque abbia mai condiviso. I tempi di inattività rompono i contenuti di altre persone, quindi il livello di uptime è più alto che per la maggior parte delle app.
Niente di tutto ciò è esotico. Sono semplicemente molti lavori sostenuti, e non finiscono mai, il che è il motivo onesto per cui la maggior parte dei team si ferma all'MVP e cerca qualcosa di manutenuto.
Costruire, acquistare, o self-hostare#
Costruirne uno da soli è il modo migliore per capire redirect, codifica e caching, e per uno strumento interno chiuso l'MVP potrebbe essere tutto ciò di cui hai mai bisogno. Costruiscilo. Imparerai più in un weekend di qualsiasi preparazione per colloqui.
Per qualsiasi cosa pubblica o rivolta alle aziende, valuta onestamente la manutenzione. Il redirect è gratuito; la gestione degli abusi, il TLS per domini personalizzati, la pipeline di analisi, e il turno di reperibilità non lo sono. Se vuoi il controllo senza scriverlo da zero, puoi fare il self-hosting di un servizio esistente, ed Elido fornisce un percorso di self-hosting esattamente per questo, con il post sulle opzioni open-source che le mette a confronto fianco a fianco. Se preferisci esternalizzarlo completamente, la soluzione per sviluppatori e la guida rapida all'API e agli SDK ti forniscono un livello di redirect di produzione senza il backlog sopra.
Correlati sul blog#
- Come funzionano gli URL shortener - il primer concettuale, senza codice richiesto.
- Raggiungere p95 sotto 15ms per i redirect - il riferimento ingegneristico su un percorso di redirect ottimizzato.
- Strategia di cache per i redirect URL - la cache a due livelli in profondità.
- Click ingestion fire-and-forget - disaccoppiare le analisi dal redirect.
- URL shortener self-hosted - le opzioni open-source se preferisci non costruire da zero.
Prova Elido
Incolla un URL, ottieni un link breve
Senza registrazione. Il link vive 30 giorni. Iscriviti per conservarlo.
Gratis, nessuna registrazione richiesta · 2 al giorno