Le cauchemar de débogage HTTP/HTTPS : 24 heures à traverser l'enfer des Mixed Content
J'ai passé 24 heures à déboguer pourquoi mon application React continuait à faire des requêtes HTTP depuis des pages HTTPS — même si mon code les convertissait. Le coupable m'a choqué.
---
Mise à jour (novembre 2025) : STRAŦUM est maintenant en Private Alpha ! La plateforme marketing à 9 agents mentionnée dans cet article accepte les premiers testeurs. Demande l'accès sur stratum.chandlernguyen.com ou lis l'histoire complète du lancement.
---
Contexte : La saga de la plateforme marketing continue
Tu te souviens de l'article de septembre où je disais que je faisais un speed run d'une plateforme marketing à 10 agents en faisant des siestes ? Quatre semaines plus tard, j'avais 3 agents fonctionnels et je visais octobre/novembre pour le lancement alpha.
Eh bien, on est fin octobre maintenant. Il est temps de faire un point d'avancement.
Les bonnes nouvelles :
- La plateforme a enfin un nom : STRAŦUM (Intelligence Over Execution)
- Des directives de marque et un design system complets (il s'avère que le branding prend plus de temps que le code)
- 9 des 10 agents construits et intégrés
- L'architecture multi-tenant qui fonctionne vraiment
- Dernière étape : préparation pour le test en pre-alpha sur invitation uniquement
Le bilan de réalité :
J'ai été malade pendant 10 jours après avoir pris 8 jours de congé (je sais, la vie c'est comme ça.) Ça a tout mis en pause et décalé mon calendrier. Adieu le lancement d'octobre, non ?
Mais voilà ce qu'on apprend du développement solo : tu contrôles le rythme. Pas de pression pour livrer quand tu n'es pas prêt. Pas d'investisseurs qui te soufflent dans le cou. Juste... construire correctement.
Cet article de blog parle d'un de ces moments "construire correctement" qui s'est transformé en marathon de débogage de 6 heures. Parce que juste quand je reprenais ma pleine vitesse après la maladie, ma plateforme de déploiement a décidé d'en avoir autrement.
Quand AWS tombe en panne, les ingénieurs font preuve de créativité (et le regrettent parfois)
Voici quelque chose qu'on ne t'apprend pas dans les bootcamps de code : parfois ta plateforme de déploiement disparaît tout simplement. Pas à cause de quelque chose que tu as fait, mais parce qu'AWS a décidé d'avoir une panne généralisée affectant les déploiements Vercel dans le monde entier.
C'est ainsi que s'est passé mon lundi. Mon site de production était en panne, Vercel affichait des erreurs, et j'avais exactement une pensée : « J'ai besoin d'un backup. Vite. »
Entrez Cloudflare Pages. J'en avais entendu du bien. Un super CDN, des déploiements automatiques, une configuration simple. Qu'est-ce qui pouvait bien tourner mal ?
Le narrateur : Tout. Absolument tout pouvait tourner mal.
La migration qui semblait trop facile
La migration vers Cloudflare Pages s'est déroulée étonnamment bien. J'ai connecté mon dépôt GitHub, configuré les variables d'environnement dans le tableau de bord, poussé vers main. Trois minutes plus tard : déployé.
« Wow, » me suis-je dit. « C'est presque trop facile. »
Puis j'ai ouvert le site de production.
```
Mixed Content: The page at 'https://my-site.com/...' was loaded over HTTPS,
but requested an insecure resource 'http://stratum-api.us-central1.run.app/...'
```
Ce sentiment de vide quand tu réalises que ta célébration était prématurée ? Oui, exactement ça.
Le problème : des appels HTTP depuis une page HTTPS
Mon application React faisait des requêtes HTTP vers mon API backend alors que la page elle-même était chargée en HTTPS. Les navigateurs (à juste titre) bloquent ça comme une faille de sécurité. Des erreurs Mixed Content. Chaque appel API échouait.
« Mais attends, » me suis-je dit, « j'ai ensureHttpsInProduction() dans mon code ! Il est censé convertir HTTP en HTTPS automatiquement ! »
J'ai vérifié le bundle déployé. La fonction était là. La logique était correcte. La console du navigateur montrait la conversion en cours. Alors pourquoi des requêtes HTTP passaient-elles encore ?
Première tentative de débogage : la chasse aux variables d'environnement
Peut-être que les variables d'environnement dans Cloudflare n'étaient pas prises en compte ?
```bash
# Vérifié dans le Dashboard Cloudflare
VITE_API_URL=https://stratum-api.us-central1.run.app ✓
VITE_SUPABASE_URL=https://your-project.supabase.co ✓
```
Tout en HTTPS. Tout correct.
J'ai déclenché un rebuild. Attendu. Déployé. Ouvert le site.
Même erreur. Toujours des requêtes HTTP.
Deuxième tentative : le grand réimport
Peut-être que certains fichiers n'utilisaient pas le API_BASE_URL centralisé ?
J'ai passé l'heure suivante à mettre à jour 24 fichiers pour qu'ils importent depuis @/lib/api au lieu d'utiliser directement import.meta.env.VITE_API_URL. Chaque composant effectuant des appels API a eu droit au traitement.
```typescript
// Avant
const response = await fetch(`${import.meta.env.VITE_API_URL}/api/v1/...`);
// Après
import \{ API_BASE_URL \} from '@/lib/api';
const response = await fetch(`$\{API_BASE_URL\}/api/v1/...`);
```
Poussé. Déployé. Attendu.
Toujours cassé.
À ce stade, je commence à remettre mes choix de vie en question.
Le coup de théâtre : des fichiers manquants dans Git
Mais attends, ça empire.
En cherchant pourquoi mon enforcement HTTPS ne fonctionnait pas, j'ai découvert quelque chose de terrifiant. Le fichier api.ts contenant ensureHttpsInProduction() n'était même pas dans mon dépôt Git.
Ni authService.ts. Ni csvSanitizer.ts. Trois fichiers frontend critiques, tout simplement... absents.
Comment ? Le fichier .gitignore avait ceci :
```
# Python stuff
lib/
build/
dist/
```
Ça semble raisonnable pour Python, non ? Sauf que mes utilitaires frontend vivaient dans apps/web/src/lib/. Le pattern large lib/ ignorait accidentellement tout mon répertoire lib frontend !
Ça voulait dire :
1. Cloudflare construisait depuis le dépôt (sans ces fichiers)
2. Mon développement local avait ces fichiers (fonctionnant bien en local)
3. J'avais AUCUNE IDÉE qu'ils n'étaient pas trackés
La correction :
```diff
# .gitignore - Avant
-lib/
# .gitignore - Après
+apps/api/lib/ # Spécifique Python
+!apps/web/src/lib/ # Inclure explicitement le lib frontend
```
J'ai ajouté les fichiers manquants, commité, poussé. Cloudflare avait maintenant le code d'enforcement HTTPS !
Sauf que... les erreurs HTTP continuaient.
Troisième tentative : la validation au moment du build
À ce stade, je remets tout en question. « Tu sais quoi ? » me suis-je dit. « Si ça continue à arriver, j'ai besoin d'EMPÊCHER ça d'atteindre la production. »
J'ai écrit un plugin Vite qui fait échouer le build s'il détecte des URLs HTTP en production :
```typescript
function validateProductionUrls(mode: string) \{
if (mode !== 'production') return;
const apiUrl = process.env.VITE_API_URL || '';
if (apiUrl && apiUrl.trim().startsWith('http://')) {
if (!apiUrl.includes('localhost') && !apiUrl.includes('127.0.0.1')) {
throw new Error(
`❌ HTTPS ENFORCEMENT FAILED
Environment Variable: VITE_API_URL
Current Value: ${apiUrl\}
This will cause Mixed Content errors in production!`
);
}
}
}
```
Génial, non ? Maintenant c'est IMPOSSIBLE de déployer avec des URLs HTTP.
Déployé à nouveau. Le build a réussi (les variables d'environnement étaient en HTTPS). Le site s'est chargé.
Même. Putain. D'erreur.
Le moment d'illumination : des fichiers locaux étaient déployés
Tard (très tard) dans la soirée, j'ai eu une révélation.
J'ai revérifié le bundle JavaScript déployé. J'ai vraiment regardé cette fois. L'URL à l'intérieur était :
```javascript
"http://stratum-api.us-central1.run.app"
```
Mais mes variables d'environnement Cloudflare étaient en HTTPS. Alors d'où venait cette URL HTTP ?
Puis ça m'a frappé. Mon fichier .env.production local.
```bash
# apps/web/.env.production (FICHIER LOCAL)
VITE_API_URL=http://stratum-api.us-central1.run.app
```
Cloudflare Pages déployait mon fichier d'environnement local au lieu d'utiliser les variables du tableau de bord !
J'ai vérifié .cloudflare-pages-ignore :
```
# Environment files
.env
.env.local
.env.development
.env.test
# .env.production ← MANQUANT !
```
Je me suis pris la tête dans les mains.
La correction : une seule ligne
```diff
# apps/web/.cloudflare-pages-ignore
.env
.env.local
.env.development
.env.test
+.env.production
```
Déployé. Attendu.
Une erreur différente cette fois ! Progrès !
```
Access to fetch at 'https://stratum-api.us-central1.run.app/...'
from origin 'https://preview-xyz.stratum-marketing-suite.pages.dev'
has been blocked by CORS policy
```
Des erreurs CORS ! De magnifiques, magnifiques erreurs CORS ! Ça voulait dire que HTTPS fonctionnait !
Mais attendez, il y a encore la suite : la conspiration du cache
Correction du CORS. Déployé à nouveau. Ouvert mon domaine personnalisé.
Des erreurs HTTP à nouveau.
Quoi ?!
Il s'avère que le CDN de Cloudflare mettait agressivement en cache l'ancien bundle. Le nouveau déploiement (avec HTTPS) était en ligne à l'URL de prévisualisation, mais mon domaine personnalisé servait du contenu mis en cache avec des URLs HTTP.
La purge du cache chez Cloudflare nécessite :
1. De trouver les bons paramètres de zone (pas dans le tableau de bord Pages)
2. De naviguer dans les paramètres de domaine (pas évident)
3. De purger manuellement le cache (pour chaque déploiement)
Après des heures à déboguer les problèmes HTTP/HTTPS, j'ai pris une décision.
Le retour à Vercel : parfois l'ennui c'est mieux
AWS était remonté. Vercel fonctionnait à nouveau.
J'ai tout migré vers Vercel. Pourquoi ?
1. Invalidation automatique du cache - Pas de purge manuelle nécessaire
2. Gestion plus simple des variables d'environnement - Ce que tu configures, c'est ce que tu obtiens
3. Débogage plus rapide - Moins d'infrastructure à comprendre
4. Éprouvé - Je connais ses bizarreries
Le déploiement Vercel a pris 3 minutes. Pas d'erreurs HTTP. Pas de problèmes de cache. Ça a juste... fonctionné.
Ce que j'ai appris (à la dure)
1. Toujours ignorer .env.production dans les plateformes de déploiement
```
# .vercelignore
# .cloudflare-pages-ignore
# .netlify-ignore
.env
.env.local
.env.development
.env.test
.env.production ← N'OUBLIE PAS CELUI-CI
```
2. Les patterns .gitignore larges sont dangereux dans les monorepos
```diff
# ❌ Mauvais - Ignore les dossiers lib frontend ET backend
-lib/
-build/
-dist/
# ✅ Bon - Spécifique à chaque contexte
+apps/api/lib/ # Spécifique Python
+apps/api/build/
+apps/api/dist/
+apps/web/dist/ # Output Vite uniquement
```
Demande-toi toujours : « Ce pattern pourrait-il accidentellement ignorer quelque chose d'important ? »
Dans un monorepo avec plusieurs langages (Python + TypeScript), des patterns larges prévus pour un écosystème peuvent accidentellement ignorer des fichiers critiques d'un autre.
3. La validation au moment du build en vaut quand même la peine
Même si elle n'a pas détecté le problème du fichier local, la validation au moment du build empêche les *futures* mauvaises configurations :
```typescript
// vite.config.ts
export default defineConfig((\{ mode \}) => \{
validateProductionUrls(mode);
return {
// ... config
\};
});
```
4. La défense multi-couches fonctionne
Notre architecture finale a TROIS couches :
- Au moment du build : Fait échouer le build si des URLs HTTP sont détectées
- Au moment de l'exécution : Convertit HTTP → HTTPS si la page est chargée en HTTPS
- Au déploiement : Exclut les fichiers .env locaux
5. Les URLs de prévisualisation sont tes amies
Teste toujours sur l'URL de prévisualisation en premier. Si ça fonctionne là mais pas sur ton domaine personnalisé, c'est généralement un problème de cache.
6. Connais les bizarreries de ta plateforme
- Vercel : Simple, invalide le cache automatiquement, les variables d'environnement « fonctionnent juste »
- Cloudflare Pages : Super CDN, mais purge manuelle du cache et configuration plus complexe
Le code qui m'a sauvé
Voici la fonction finale ensureHttpsInProduction() :
```typescript
function ensureHttpsInProduction(url: string): string \{
// Convertir uniquement dans le contexte du navigateur quand le site est chargé en HTTPS
if (typeof window !== 'undefined' && window.location.protocol === 'https:') {
// Ne pas convertir les URLs localhost/127.0.0.1 (développement local)
if (url.startsWith('http://') &&
!url.includes('localhost') &&
!url.includes('127.0.0.1')) {
console.warn('[API] Converting HTTP to HTTPS:', url);
return url.replace('http://', 'https://');
\}
}
return url;
}
```
Et la validation au moment du build dans vite.config.ts :
```typescript
function validateProductionUrls(mode: string) \{
if (mode !== 'production') return;
const apiUrl = process.env.VITE_API_URL || '';
// Vérifier HTTP (doit être HTTPS)
if (apiUrl && apiUrl.trim().startsWith('http://')) {
if (!apiUrl.includes('localhost') && !apiUrl.includes('127.0.0.1')) {
throw new Error(`
❌ HTTPS ENFORCEMENT FAILED
Environment Variable: VITE_API_URL
Current Value: ${apiUrl\}
Mixed Content Error Prevention:
Browsers block HTTP requests from HTTPS pages.
Fix: Update environment variables to use HTTPS URLs.
`);
}
}
}
```
La vraie leçon : déboguer, c'est faire de l'archéologie
Ce n'était pas un problème de code. C'était une expédition d'archéologie de configuration.
Les vrais bugs étaient :
1. ✅ Des patterns .gitignore larges ignorant des fichiers frontend critiques
2. ✅ .env.production absent du .cloudflare-pages-ignore
3. ✅ La mise en cache agressive du CDN masquant la correction
4. ✅ Suppositions sur la priorité des variables d'environnement
La solution technique était une ligne dans un fichier .ignore.
Le débogage ? Ça a pris 6 heures, 14 déploiements, et beaucoup trop de café.
Est-ce que ça en valait la peine ?
Absolument. Voici ce que j'en ai tiré :
1. Compréhension approfondie des politiques de sécurité Mixed Content
2. Validation au moment du build qui prévient les problèmes futurs
3. Enforcement HTTPS multi-couches indépendant de la plateforme
4. Une vraie appréciation de la simplicité de Vercel
Et surtout : une excellente histoire de débogage à partager. :P
Le journal Git raconte l'histoire
```bash
2033b9a fix: add .env.production to .vercelignore
3555390 docs: migrate deployment documentation from Cloudflare Pages to Vercel
a4edb09 chore: force clean Cloudflare Pages rebuild
590c271 fix: enhance ensureHttpsInProduction logging
15d69c6 chore: force rebuild of UserProfile bundle
a1c345f fix: add .env.production to cloudflare-pages-ignore ← LE FIX .ENV
635d80d docs: update documentation for Cloudflare Pages migration
edfa611 feat: add build-time HTTPS enforcement
802c1e9 fix: enforce HTTPS for all API calls across frontend
26f6b87 refactor: comprehensive .gitignore audit and cleanup
3758a9c fix: unignore frontend lib directory and add missing files ← LE FIX GITIGNORE
```
Chaque commit représentait autrefois une heure de débogage, mais avec Claude Code, dieu merci, ma vitesse était bien supérieure. Une hypothèse testée. Une leçon apprise.
Pour les autres ingénieurs qui se battent contre les erreurs Mixed Content
Si tu lis ceci parce que tu débogues le même problème, voici ta checklist :
1. Vérifie tes variables d'environnement :
```bash
# Affiche les vraies valeurs utilisées
console.log('API URL:', import.meta.env.VITE_API_URL);
```
2. Vérifie ton bundle déployé :
```bash
# Télécharge et cherche dans le bundle JavaScript
curl https://your-site.com/assets/index-ABC123.js | grep "http://"
```
3. Vérifie tes fichiers ignore :
```bash
# Assure-toi que .env.production est exclu
cat .vercelignore
cat .cloudflare-pages-ignore
cat .netlify-ignore
```
4. Vérifie ton .gitignore (Monorepos) :
```bash
# Assure-toi que des fichiers critiques ne sont pas ignorés
git ls-files apps/web/src/lib/ # Devrait afficher api.ts, etc.
# Si vide, cherche des patterns larges
grep "^lib/" .gitignore # ❌ Trop large
grep "^apps/api/lib/" .gitignore # ✅ Spécifique
```
5. Vérifie ton cache :
```bash
# Teste sur l'URL de prévisualisation en premier
# Si la prévisualisation fonctionne mais pas la production = problème de cache
```
6. Ajoute de la validation au moment du build :
```typescript
// Empêche que ça n'arrive plus jamais
if (mode === 'production' && url.startsWith('http://')) \{
throw new Error('HTTPS required in production!');
\}
```
La checklist de migration que j'aurais voulu avoir
Lors du changement de plateforme de déploiement :
- [ ] Lister TOUTES les variables d'environnement de l'ancienne plateforme
- [ ] Configurer les variables d'environnement dans la nouvelle plateforme EN PREMIER
- [ ] Ajouter TOUS les fichiers .env au .ignore (y compris .env.production)
- [ ] Vérifier que .gitignore n'ignore pas des fichiers critiques (lancer git ls-files pour vérifier)
- [ ] Tester sur l'URL de prévisualisation avant le domaine personnalisé
- [ ] Vérifier le bundle déployé pour les URLs HTTP
- [ ] Vérifier les paramètres CORS si le backend est séparé
- [ ] Documenter les bizarreries spécifiques à la plateforme
Toujours en train de coder, d'apprendre, et de tout casser (parfois)
Six heures de débogage pour une correction d'une ligne. C'est l'ingénierie logicielle en résumé.
Le code qu'on livre est important, bien sûr. Mais les compétences de débogage qu'on développe ? Ce sont elles qui font de nous de meilleurs ingénieurs.
La prochaine fois que ma plateforme de déploiement tombera en panne (et ça arrivera), je serai prêt. J'ai :
- ✅ Un enforcement HTTPS indépendant de la plateforme
- ✅ Une validation au moment du build
- ✅ Une meilleure compréhension de la priorité des variables d'environnement
- ✅ Une stratégie de déploiement de secours
Et j'espère que cet article de blog épargnera à quelqu'un d'autre quelques-unes de ces 6 heures. :)
Tu as déjà eu un « correctif d'une ligne » qui t'a pris un temps embarrassant à trouver ? J'adorerais entendre tes histoires de détective du débogage — la misère aime la compagnie !
Cordialement, Chandler





