Changer le thème

Workers + KV : raccourcisseur maison, du débutant à la pratique

Easton editorial illustration: lifecycle journey rail

Pourquoi mon propre raccourcisseur ?

Pendant près de deux ans, j’utilisais un service de liens courts tiers. Un matin, tous les liens étaient morts — le fournisseur annonçait la fermeture. Les centaines de liens partagés sur les réseaux sociaux renvoyaient en 404.

J’ai alors cherché une solution 100 % à moi : données sous contrôle, personnalisation libre, plus de dépendance à un tiers qui disparaît.

Cloudflare Workers + KV colle parfaitement :

  • Quota gratuit très large (100 000 requêtes/jour)
  • 200+ nœuds, accès rapide partout
  • Déploiement en quelques lignes
  • Données que vous gardez aussi longtemps que vous voulez

Cet article explique comment j’ai construit mon raccourcisseur avec Workers + KV : codes personnalisés, statistiques, etc. Le code est inclus — comptez une demi-heure pour être en ligne.

Pourquoi Workers + KV ?

Qu’est-ce que Cloudflare Workers ?

En bref : des fonctions serverless sur le réseau edge de Cloudflare. Vous déployez le code ; il se réplique sur 200+ points de présence. L’utilisateur est routé vers le nœud le plus proche — latence minimale.

Quota gratuit généreux :

  • 100 000 requêtes par jour
  • 10 ms de CPU par requête
  • Largement suffisant pour un usage perso ou une petite équipe

Atouts du stockage KV

KV est la base clé-valeur distribuée de Cloudflare, pensée pour le edge :

  • Lecture rapide : médiane ~12 ms grâce au cache edge
  • Sync mondiale : propagation globale en ~60 s après écriture
  • Quota gratuit : 100 000 lectures et 1 000 écritures par jour

Pour un raccourcisseur, c’est un match naturel :

  • Code court = clé, URL = valeur
  • Peu d’écritures, beaucoup de lectures
  • Accès rapide partout dans le monde
100 000/jour
Quota gratuit
100 000 requêtes Workers par jour
12 ms
Lecture KV
Médiane, données en cache edge
200+
Nœuds mondiaux
Accès rapide partout

Comparaison avec un service tiers

CritèreService tiersWorkers + KV maison
DonnéesChez le tiersSous votre contrôle
PersonnalisationFixeLibre
StabilitéRisque de fermetureSoutenu par Cloudflare
PublicitéPage intermédiaire possibleAucune
CoûtParfois payantQuasi gratuit
VitesseSelon le fournisseurRéseau edge mondial

Construire le raccourcisseur de zéro

Assez de théorie — passons à la pratique.

Préparation

1. Compte Cloudflare

Inscrivez-vous sur cloudflare.com — l’offre gratuite suffit.

2. Installer Wrangler CLI

Wrangler est l’outil officiel pour gérer les projets Workers.

npm install -g wrangler
# ou avec yarn
yarn global add wrangler

Puis connectez-vous :

wrangler login

Le navigateur s’ouvre pour l’autorisation — acceptez.

3. Créer le projet

mkdir my-shortlink
cd my-shortlink
wrangler init

Suivez les invites ; un projet JavaScript convient (TypeScript aussi).

Étape 1 : créer l’espace de noms KV

Le KV exige d’abord un « namespace », un peu comme une table dans une base.

# Production
wrangler kv namespace create SHORTLINKS
# Prévisualisation (tests locaux)
wrangler kv namespace create SHORTLINKS --preview

Vous obtenez deux ID, par exemple :

{ binding = "SHORTLINKS", id = "abc123..." }
{ binding = "SHORTLINKS", preview_id = "def456..." }

Important : notez ces ID pour la suite.

Éditez wrangler.toml :

name = "my-shortlink"
main = "src/index.js"
compatibility_date = "2025-12-01"

# Liaison KV
kv_namespaces = [
  { binding = "SHORTLINKS", id = "votre ID production", preview_id = "votre ID preview" }
]

binding = "SHORTLINKS" permet d’accéder au KV via env.SHORTLINKS dans le code.

Étape 2 : fonctionnalité de base

Ouvrez src/index.js :

export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    const path = url.pathname.slice(1); // sans le / initial

    if (path === '') {
      return new Response('Bienvenue sur le service de liens courts !', { status: 200 });
    }

    if (request.method === 'GET') {
      const targetUrl = await env.SHORTLINKS.get(path);
      if (targetUrl) {
        return Response.redirect(targetUrl, 301);
      } else {
        return new Response('Lien court introuvable', { status: 404 });
      }
    }

    if (request.method === 'POST') {
      try {
        const body = await request.json();
        const { url: targetUrl, code } = body;

        if (!targetUrl) {
          return new Response('Paramètre url manquant', { status: 400 });
        }

        const shortCode = code || generateRandomCode();

        const existing = await env.SHORTLINKS.get(shortCode);
        if (existing) {
          return new Response('Code court déjà utilisé', { status: 409 });
        }

        await env.SHORTLINKS.put(shortCode, targetUrl);

        return new Response(JSON.stringify({
          shortCode,
          shortUrl: `${url.origin}/${shortCode}`,
          targetUrl
        }), {
          status: 201,
          headers: { 'Content-Type': 'application/json' }
        });
      } catch (error) {
        return new Response('Format de requête invalide', { status: 400 });
      }
    }

    return new Response('Méthode non autorisée', { status: 405 });
  }
};

function generateRandomCode(length = 6) {
  const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  let code = '';
  for (let i = 0; i < length; i++) {
    code += chars.charAt(Math.floor(Math.random() * chars.length));
  }
  return code;
}

Logique :

  1. GET : visite de yourdomain.com/abc123 → lecture KV → redirection 301
  2. POST : url + code optionnel ; génération aléatoire si pas de code → écriture KV
  3. generateRandomCode : 6 caractères alphanumériques

Étape 3 : tests locaux

wrangler dev

Serveur local, en général http://localhost:8787.

Créer un lien :

curl -X POST http://localhost:8787 \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'

Réponse :

{
  "shortCode": "aBc123",
  "shortUrl": "http://localhost:8787/aBc123",
  "targetUrl": "https://example.com"
}

Tester la redirection : ouvrez http://localhost:8787/aBc123 — vous devez arriver sur https://example.com.

Si tout fonctionne, la base est OK.

Étape 4 : code court personnalisé

Le code accepte déjà un code dans le POST :

curl -X POST http://localhost:8787 \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com", "code": "my-link"}'

Pour plus de robustesse, validez le format :

if (code) {
  if (!/^[a-zA-Z0-9-]+$/.test(code)) {
    return new Response('Format de code invalide (lettres, chiffres, tirets uniquement)', { status: 400 });
  }
  if (code.length < 3 || code.length > 20) {
    return new Response('Longueur du code : entre 3 et 20 caractères', { status: 400 });
  }
}

Cela évite des codes bizarres (caractères spéciaux, longueur excessive).

Étape 5 : statistiques de visites

Souvent, on veut aussi le nombre de clics par lien.

Idée :

  • À chaque visite : incrémenter un compteur
  • Stocker sous stats:{shortCode} dans le KV

Modifiez la partie GET :

if (request.method === 'GET') {
  const targetUrl = await env.SHORTLINKS.get(path);
  if (targetUrl) {
    const statsKey = `stats:${path}`;
    env.SHORTLINKS.get(statsKey).then(count => {
      const newCount = (parseInt(count) || 0) + 1;
      env.SHORTLINKS.put(statsKey, newCount.toString());
    });
    return Response.redirect(targetUrl, 301);
  } else {
    return new Response('Lien court introuvable', { status: 404 });
  }
}

Endpoint de consultation :

if (path.startsWith('stats/')) {
  const shortCode = path.slice(6);
  const statsKey = `stats:${shortCode}`;
  const count = await env.SHORTLINKS.get(statsKey);
  return new Response(JSON.stringify({
    shortCode,
    visits: parseInt(count) || 0
  }), {
    headers: { 'Content-Type': 'application/json' }
  });
}

Accès : http://localhost:8787/stats/abc123 pour le nombre de visites.

Note : le KV n’est pas atomique — en forte concurrence, le compteur peut dériver. Pour de la précision stricte, utilisez Durable Objects. Pour un usage perso, cette approche suffit souvent.

Étape 6 : déploiement en production

wrangler deploy

URL du type https://my-shortlink.your-subdomain.workers.dev — votre raccourcisseur, accessible mondialement.

Domaine personnalisé (optionnel) :

Avec un domaine (ex. short.example.com) :

  1. Workers & Pages dans le Dashboard
  2. Sélectionnez votre Worker
  3. Settings > Triggers
  4. Ajoutez un Custom Domain

Exemple de lien : https://short.example.com/abc123.

Fonctions avancées

1. Création par lot

if (request.method === 'POST' && url.pathname === '/batch') {
  try {
    const body = await request.json();
    const links = body.links;

    if (!Array.isArray(links)) {
      return new Response('links doit être un tableau', { status: 400 });
    }

    const results = [];
    for (const link of links) {
      const { url: targetUrl, code } = link;
      const shortCode = code || generateRandomCode();
      const existing = await env.SHORTLINKS.get(shortCode);
      if (!existing) {
        await env.SHORTLINKS.put(shortCode, targetUrl);
        results.push({ shortCode, targetUrl, success: true });
      } else {
        results.push({ shortCode, targetUrl, success: false, error: 'Code court déjà utilisé' });
      }
    }
    return new Response(JSON.stringify({ results }), {
      headers: { 'Content-Type': 'application/json' }
    });
  } catch (error) {
    return new Response('Format de requête invalide', { status: 400 });
  }
}

Appel :

curl -X POST http://localhost:8787/batch \
  -H "Content-Type: application/json" \
  -d '{
    "links": [
      {"url": "https://example1.com", "code": "link1"},
      {"url": "https://example2.com"}
    ]
  }'

2. Expiration (TTL)

Le KV accepte un TTL :

await env.SHORTLINKS.put(shortCode, targetUrl, {
  expirationTtl: 86400 // suppression après 24 h (secondes)
});

TTL choisi par l’utilisateur :

const { url: targetUrl, code, ttl } = body;
const options = {};
if (ttl) {
  options.expirationTtl = parseInt(ttl);
}
await env.SHORTLINKS.put(shortCode, targetUrl, options);

3. Contrôle d’accès

Limiter la création de liens avec un token API :

// wrangler.toml
# [vars]
# API_TOKEN = "your-secret-token"

if (request.method === 'POST') {
  const token = request.headers.get('Authorization');
  if (token !== `Bearer ${env.API_TOKEN}`) {
    return new Response('Non autorisé', { status: 401 });
  }
  // ... création
}

Appel avec token :

curl -X POST http://localhost:8787 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your-secret-token" \
  -d '{"url": "https://example.com"}'

4. Limitation de débit (anti-abus)

const clientIp = request.headers.get('CF-Connecting-IP');
const rateLimitKey = `ratelimit:${clientIp}`;

const count = await env.SHORTLINKS.get(rateLimitKey);
if (parseInt(count) >= 10) {
  return new Response('Trop de requêtes, réessayez plus tard', { status: 429 });
}

const newCount = (parseInt(count) || 0) + 1;
await env.SHORTLINKS.put(rateLimitKey, newCount.toString(), {
  expirationTtl: 3600
});

Limite : 10 créations par IP et par heure.

Performance et bonnes pratiques

Optimisations

1. Cache

Le KV est déjà rapide (~12 ms médiane). Cache mémoire optionnel dans le Worker :

const cache = new Map();
const targetUrl = cache.get(path) || await env.SHORTLINKS.get(path);
if (targetUrl) {
  cache.set(path, targetUrl);
  return Response.redirect(targetUrl, 301);
}

La mémoire Worker n’est pas persistante — perdue au redémarrage.

2. Réduire les écritures KV

Quota : 1 000 écritures/jour. Stats à chaque clic = risque de dépassement.

Options : Durable Objects (atomique), écrire tous les N clics, ou Cloudflare Analytics Engine.

3. CORS

Pour appels depuis un frontend :

const corsHeaders = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
  'Access-Control-Allow-Headers': 'Content-Type',
};

if (request.method === 'OPTIONS') {
  return new Response(null, { headers: corsHeaders });
}

return new Response(body, {
  headers: { ...headers, ...corsHeaders }
});

Coûts

Quota gratuit :

  • 100 000 requêtes Workers/jour
  • KV : 100 000 lectures, 1 000 écritures/jour
  • 10 ms CPU par requête

Hors quota (Workers Paid, à partir de 5 $/mois) :

  • 0,50 $ / million de requêtes
  • KV lecture : 0,50 $ / million
  • KV écriture : 5,00 $ / million
  • Stockage : 0,50 $ / Go/mois

Usage perso : rarement au-delà du gratuit. Petite équipe : souvent OK avec des dizaines de milliers de visites/jour.

Économiser les requêtes :

  • 301 (cache navigateur) plutôt que 302
  • Pages statiques sur Workers Pages
  • TTL pour liens expirés

Sécurité

1. Liens malveillants

Service public = risque d’abréger des URLs dangereuses.

  • Token API
  • Liste noire de domaines
  • Journal IP du créateur

2. Collisions

Vérifiez l’existence malgré l’espace énorme :

const existing = await env.SHORTLINKS.get(shortCode);
if (existing) {
  return new Response('Code court déjà utilisé', { status: 409 });
}

3. URL cible

Liste blanche :

const allowedDomains = ['example.com', 'mywebsite.com'];
const targetDomain = new URL(targetUrl).hostname;
if (!allowedDomains.some(d => targetDomain.endsWith(d))) {
  return new Response('Domaine cible non autorisé', { status: 403 });
}

Mon retour d’expérience

Plusieurs mois d’usage :

Avantages :

  • Rapide : latence souvent < 50 ms, bien mieux que mon ancien tiers
  • Stable : réseau Cloudflare, quasi pas de panne
  • Serein : déployé une fois, montée en charge automatique
  • Gratuit : quelques milliers de requêtes/jour, dans le quota

Écueils :

  • Latence d’écriture KV : cohérence finale, synchro globale en dizaines de secondes — peu gênant (on crée rarement puis on partage tout de suite)
  • Stats imprécises : pas d’atomique KV ; Durable Objects si vous voulez de la précision (plus cher hors quota)

Pistes :

  • Dashboard Workers Pages
  • Cloudflare Analytics (sources, géo)
  • QR codes pour le partage hors ligne

Synthèse

Workers + KV pour un raccourcisseur : rapide et économique. Moins de 100 lignes de cœur, un wrangler deploy, et vos données restent chez vous.

Si le besoin vous parle, essayez — le code est là, une demi-heure suffit souvent.

Rappel des étapes :

  1. Compte Cloudflare + Wrangler
  2. Namespace KV + wrangler.toml
  3. GET (redirection) + POST (création)
  4. Tests locaux, déploiement

Ensuite : stats, lot, expiration… le code est à vous — c’est satisfaisant.

Des questions ? Laissez un commentaire — bon déploiement !

Construire un raccourcisseur avec Cloudflare Workers + KV

Mise en place complète : création de liens, redirection, statistiques de visites, en ligne en une demi-heure

⏱️ Estimated time: 30 min

  1. 1

    Step 1: Préparation : compte Cloudflare et Wrangler CLI

    Étape 1 : compte Cloudflare
    • Inscrivez-vous sur cloudflare.com — l'offre gratuite suffit

    Étape 2 : installer Wrangler CLI
    • Wrangler est l'outil officiel en ligne de commande pour gérer les projets Workers
    • Exécutez : npm install -g wrangler
    • Ou : yarn global add wrangler
    • Puis connectez-vous : wrangler login
    • Le navigateur s'ouvre pour l'autorisation — acceptez

    Étape 3 : créer le projet
    • mkdir my-shortlink
    • cd my-shortlink
    • wrangler init
    • Suivez les invites ; choisissez un projet JavaScript (TypeScript possible aussi)
  2. 2

    Step 2: Créer l'espace de noms KV et configurer wrangler.toml

    Créer l'espace de noms KV :

    Méthode 1 : Dashboard Cloudflare
    • Workers & Pages → KV
    • Create a namespace
    • Nom (ex. SHORTLINKS), puis créer

    Méthode 2 : ligne de commande
    • wrangler kv:namespace create SHORTLINKS

    Configurer wrangler.toml :
    À la fin du fichier, ajoutez la liaison KV :

    [[kv_namespaces]]
    binding = "SHORTLINKS"
    id = "votre ID d'espace de noms"

    Dans le code, accédez au KV via env.SHORTLINKS
  3. 3

    Step 3: Code cœur : création de liens et redirection

    Fonctions principales :

    1. Génération du code court :
    • Code personnalisé ou aléatoire
    • 6 caractères alphanumériques possibles
    • 62^6 ≈ 56,8 milliards de combinaisons — collisions rares

    2. Stockage KV :
    • Code court = clé, URL d'origine = valeur
    • Métadonnées possibles (date de création, nombre de visites, etc.)

    3. Redirection :
    • GET : lire l'URL d'origine dans le KV
    • Réponse 302 vers l'URL cible

    4. Statistiques :
    • Compteur et horodatage des visites
    • Stockables dans les métadonnées KV

    Exemples :
    • GET (redirection) : code court depuis le chemin, lecture KV, 302 si trouvé, 404 sinon
    • POST (création) : URL cible + code court optionnel, génération, vérification collision, écriture KV, retour de l'URL courte
  4. 4

    Step 4: Tests locaux et déploiement en production

    Tests locaux :

    1. wrangler dev pour le serveur local
    2. Tester création et redirection

    Avec curl :
    • Créer un lien :
    curl -X POST http://localhost:8787/create -H "Content-Type: application/json" -d '{"url":"https://example.com"}'

    • Visiter le lien court :
    curl -L http://localhost:8787/abc123
    (redirection vers l'URL d'origine)

    Déploiement :
    • wrangler deploy
    • Wrangler déploie le Worker sur Cloudflare
    • URL du type : your-worker-name.your-subdomain.workers.dev
    • Votre raccourcisseur est en ligne !
  5. 5

    Step 5: Fonctions avancées et sécurité

    Avancé : 1) statistiques (compteur et horodatage dans les métadonnées KV, mise à jour à chaque visite) ; 2) expiration (TTL, lien invalide après échéance) ; 3) création par lot ; 4) interface d'admin (Dashboard simple via Workers Pages). Sécurité : 1) liens malveillants (token API, liste noire de domaines, IP du créateur) ; 2) collisions de codes (vérifier l'existence avant création malgré l'espace énorme) ; 3) URL cible (liste blanche de domaines autorisés). Économiser les requêtes : redirection 301 (cache navigateur) plutôt que 302 ; pages statiques sur Workers Pages ; TTL pour nettoyer les liens expirés.

FAQ

Pourquoi héberger son propre raccourcisseur ? Quels avantages Workers + KV ?
Un service tiers fermé du jour au lendemain et des centaines de liens en 404 ? En maison, les données vous appartiennent, la personnalisation est totale, plus de risque de « fuite » du fournisseur.

Avantages Workers + KV :
• Quota gratuit très large (100 000 requêtes/jour)
• 200+ nœuds edge, latence faible partout
• Quelques lignes de code pour démarrer
• Données sous votre contrôle, durée de conservation à votre choix

Comparaison avec un tiers :
• Données (chez le tiers vs entièrement chez vous)
• Personnalisation (fixe vs libre)
• Stabilité (risque de fermeture vs Cloudflare)
• Publicité (page intermédiaire possible vs aucune)
• Coût (payant possible vs quasi gratuit)
• Vitesse (selon le fournisseur vs réseau edge mondial)
Quels avantages du stockage KV pour un raccourcisseur ?
KV (Key-Value) est la base clé-valeur distribuée de Cloudflare, optimisée pour le edge.

Atouts KV :
• Lecture rapide, médiane ~12 ms (cache sur les nœuds edge)
• Synchronisation mondiale : propagation globale en ~60 s après écriture
• Quota gratuit : 100 000 lectures et 1 000 écritures par jour

Pour les liens courts, le KV est idéal :
• Code court = clé, URL = valeur
• Profil lecture-intensive (peu de créations, beaucoup de clics)
• Distribution mondiale

Quotas gratuits :
• Workers : 100 000 requêtes/jour
• KV : 100 000 lectures, 1 000 écritures/jour
• Suffisant pour un usage perso ; souvent OK pour une petite équipe (dizaines de milliers de visites/jour)

Au-delà du gratuit (Workers Paid, à partir de 5 $/mois) :
• 0,50 $ / million de requêtes Workers
• 0,50 $ / million de lectures KV
• 5,00 $ / million d'écritures KV
• 0,50 $ / Go/mois de stockage KV
Comment construire un raccourcisseur de zéro ? Quelles étapes ?
Préparation :

1. Compte Cloudflare (cloudflare.com, offre gratuite)
2. Wrangler (npm install -g wrangler, puis wrangler login)
3. Projet (mkdir my-shortlink, cd, wrangler init)

KV et configuration :
• Dashboard : Workers & Pages → KV → Create a namespace (ex. SHORTLINKS)
• Ou CLI : wrangler kv:namespace create SHORTLINKS

wrangler.toml :
• Ajouter la liaison KV en fin de fichier
• Accès via env.SHORTLINKS dans le code

Code cœur :

GET (redirection) :
• Code court depuis le chemin
• Lecture de l'URL dans le KV
• 302 si trouvé, 404 sinon

POST (création) :
• URL cible + code court optionnel
• Génération aléatoire si pas de code fourni
• Vérification d'existence (anti-collision)
• Écriture KV, retour de l'URL courte

Test et déploiement :
• wrangler dev en local
• wrangler deploy en production
Comment implémenter les fonctions cœur du raccourcisseur ?
Implémentation :

1) Code court :
• Personnalisé ou aléatoire
• 6 caractères alphanumériques, 62^6 ≈ 56,8 milliards — collisions rares

2) Stockage KV :
• Clé = code court, valeur = URL
• Métadonnées : date de création, compteur, etc.

3) Redirection :
• GET : lecture KV, 302 vers l'URL cible

4) Statistiques :
• Compteur et horodatage
• Métadonnées KV, incrément à chaque visite

Exemples de flux :

GET :
• Code court depuis le chemin
• Lecture KV → 302 ou 404

POST :
• URL + code optionnel
• Génération si besoin
• Vérification collision
• put KV, retour URL courte

Avancé : statistiques, expiration, lot, Dashboard Workers Pages
Quelles précautions de sécurité pour un raccourcisseur ?
Sécurité :

1) Liens malveillants :
• Service ouvert = risque d'abréger des sites dangereux
• Recommandations :
- Token API
- Liste noire de domaines connus
- Journaliser l'IP du créateur

2) Collisions de codes :
• 62^6 combinaisons — rare, mais vérifier quand même :
const existing = await env.SHORTLINKS.get(shortCode);
if (existing) {
return new Response('Code court déjà utilisé', { status: 409 });
}

3) URL cible :
• Liste blanche de domaines :
const allowedDomains = ['example.com', 'mywebsite.com'];
const targetDomain = new URL(targetUrl).hostname;
if (!allowedDomains.some(d => targetDomain.endsWith(d))) {
return new Response('Domaine cible non autorisé', { status: 403 });
}

Économiser les requêtes :
• 301 plutôt que 302 (cache navigateur)
• Pages statiques sur Workers Pages
• TTL pour liens expirés
Retour d'expérience : avantages et limites ?
Retour terrain :

Avantages :
• Rapide (latence mondiale souvent < 50 ms, bien mieux que mon ancien tiers)
• Stable (réseau Cloudflare, rarement de panne)
• Serein (déployé une fois, montée en charge automatique)
• Gratuit (quelques milliers de requêtes/jour, dans le quota)

Écueils :
• Latence d'écriture KV (cohérence finale, dizaines de secondes pour la synchro globale — peu gênant pour les liens courts, création puis accès différé)
• Stats imprécises (pas d'opérations atomiques KV ; en forte concurrence, compter via Durable Objects si précision requise — plus coûteux hors quota)

Pistes :
• Dashboard Workers Pages
• Cloudflare Analytics (sources, géo)
• Génération de QR codes pour le partage hors ligne

9 min de lecture · Publié le: 1 déc. 2025 · Mis à jour le: 27 juil. 2026

Commentaires

Connectez-vous avec GitHub pour laisser un commentaire

Easton BlogEaston Blog