Avancé

CORS — pourquoi ça bloque ?

Votre dashboard Streamlit communique avec l'API Flask via HTTP. Mais dans certains cas, le navigateur peut bloquer ces appels. Ce mécanisme s'appelle CORS (Cross-Origin Resource Sharing).

Le mécanisme CORS

CORS est un mécanisme de sécurité des navigateurs web. Il bloque les requêtes HTTP entre deux origines différentes.

Deux URLs ont des origines différentes si elles diffèrent par le protocole, le domaine ou le port :

  • http://localhost:8501 (Streamlit) et http://localhost:5000 (Flask) = origines différentes (ports différents)
  • http://localhost:5000/api/v1/ventes et http://localhost:5000/api/v1/stats = même origine

Quand un navigateur web tente d'appeler localhost:5000 depuis une page servie par localhost:8501, il vérifie d'abord que le serveur autorise cette origine. Si le serveur ne renvoie pas les bons headers CORS, le navigateur bloque la requête.

Chargement du diagramme…

Requête preflight

Pour les requêtes non triviales (avec des headers personnalisés, des méthodes autres que GET/POST, etc.), le navigateur envoie d'abord une requête OPTIONS (preflight) pour demander au serveur quelles origines il autorise. C'est une vérification préalable avant l'appel réel.

requests n'est pas concerné

CORS ne s'applique qu'aux navigateurs web. requests effectue les appels HTTP depuis le processus Python, sans passer par un navigateur. CORS ne bloque donc jamais vos appels requests.get().

python
# Fonctionne toujours, même sans configuration CORS
response = requests.get("http://localhost:5000/api/v1/ventes/par-region")

C'est la raison pour laquelle votre dashboard Streamlit fonctionne sans aucune configuration CORS : Streamlit exécute le code Python côté serveur, pas dans le navigateur.

Pourquoi CORS ne bloque pas les appels faits avec la bibliothèque requests en Python ?

Quand CORS devient un problème

CORS vous concernera si vous ajoutez :

  • Un composant JavaScript via st.components.html() dans Streamlit
  • Un client frontend React ou Vue.js qui consomme la même API
  • Un notebook Jupyter exécuté dans un navigateur avec des appels fetch()

Dans ces cas, les appels HTTP sont effectués par le navigateur (via fetch() ou XMLHttpRequest), et CORS s'applique pleinement.

Configurer flask-cors

Si CORS vous bloque, la solution côté Flask :

bash
pip install flask-cors
python
from flask import Flask
from flask_cors import CORS

app = Flask(__name__)

# Option 1 : autoriser toutes les origines (développement uniquement)
CORS(app)

# Option 2 : restreindre aux origines nécessaires (recommandé)
CORS(app, origins=["http://localhost:8501", "https://mon-dashboard.com"])

# Option 3 : restreindre par route
CORS(app, resources={r"/api/*": {"origins": "http://localhost:8501"}})

Ne jamais autoriser toutes les origines en production

CORS(app) sans restriction autorise n'importe quel site web à appeler votre API. Acceptable en développement, mais dangereux en production. Listez toujours explicitement les origines autorisées.

Headers ajoutés par flask-cors

flask-cors ajoute ces headers aux réponses :

HeaderRôleExemple
Access-Control-Allow-OriginOrigines autoriséeshttp://localhost:8501
Access-Control-Allow-MethodsMéthodes HTTP autoriséesGET, POST, OPTIONS
Access-Control-Allow-HeadersHeaders personnalisés autorisésContent-Type, Authorization

CORS = protection navigateur, pas serveur

Le serveur ne bloque rien lui-même — il indique simplement au navigateur quelles origines il autorise via ces headers. C'est le navigateur qui décide de bloquer ou non la requête en lisant ces headers. Un client comme requests ou curl ignore complètement ces headers.

Quelle commande installe le support CORS pour Flask ?

À retenir

Points clés

  • CORS est une protection navigateurrequests en Python n'est pas affecté
  • Deux origines sont différentes si le protocole, le domaine ou le port diffèrent
  • Le navigateur envoie une requête preflight (OPTIONS) avant l'appel réel
  • flask-cors ajoute les headers nécessaires côté Flask
  • En production, toujours restreindre les origines autorisées
  • Votre dashboard Streamlit fonctionne sans CORS car requests opère côté serveur

Ressources

Une API accessible publiquement pose un autre problème : comment empêcher les utilisateurs non autorisés d'y accéder ?