latapp hai 9 meses
pai
achega
7b4b171835
Modificáronse 8 ficheiros con 199 adicións e 5 borrados
  1. 82 0
      NO_CACHE_SETUP.md
  2. 11 0
      app.py
  3. 6 0
      middleware/__init__.py
  4. 39 0
      middleware/no_cache.py
  5. 6 0
      public/main/index.html
  6. 6 0
      public/register/index.html
  7. 6 0
      public/verify.html
  8. 43 5
      routes/static.py

+ 82 - 0
NO_CACHE_SETUP.md

@@ -0,0 +1,82 @@
+# Configuración para Evitar Cache del Navegador
+
+Este documento explica las implementaciones realizadas para evitar que las páginas de la carpeta `public` guarden cache en el navegador.
+
+## Cambios Realizados
+
+### 1. Archivos HTML Modificados
+
+Se agregaron meta tags de no-cache en las secciones `<head>` de todos los archivos HTML:
+
+- `public/main/index.html`
+- `public/register/index.html` 
+- `public/verify.html`
+
+**Meta tags agregados:**
+```html
+<!-- Meta tags para evitar cache -->
+<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
+<meta http-equiv="Pragma" content="no-cache">
+<meta http-equiv="Expires" content="0">
+```
+
+### 2. Servidor FastAPI - Headers HTTP
+
+#### a) Clase NoCacheStaticFiles
+
+Se creó una clase personalizada `NoCacheStaticFiles` en `routes/static.py` que extiende `StaticFiles` y agrega automáticamente headers de no-cache a todos los archivos estáticos.
+
+#### b) Funciones de Servicio HTML
+
+Se modificaron las funciones que sirven archivos HTML para incluir headers de no-cache:
+- `serve_app_html()`
+- `serve_register_html()`
+- `serve_image()`
+
+**Headers agregados:**
+```python
+headers = {
+    "Cache-Control": "no-cache, no-store, must-revalidate, max-age=0",
+    "Pragma": "no-cache",
+    "Expires": "0"
+}
+```
+
+### 3. Middleware Global
+
+Se creó un middleware global `NoCacheMiddleware` que asegura que todas las rutas relacionadas con archivos públicos tengan headers de no-cache.
+
+**Rutas cubiertas:**
+- `/` (página principal)
+- `/register` (página de registro)
+- `/verify` (página de verificación)
+- `/express/` (archivos estáticos principales)
+- `/register/` (archivos estáticos de registro)
+- `/images/` (imágenes)
+
+## Efectos de los Cambios
+
+1. **Cache del navegador:** Los archivos HTML, CSS, JS e imágenes no se guardarán en cache
+2. **Actualizaciones inmediatas:** Los cambios en archivos se reflejarán inmediatamente sin necesidad de refrescar con Ctrl+F5
+3. **Compatibilidad:** Funciona con todos los navegadores modernos
+
+## Verificación
+
+Para verificar que funciona correctamente:
+
+1. Abre las herramientas de desarrollador (F12)
+2. Ve a la pestaña "Network" 
+3. Recarga la página
+4. Verifica que en los headers de respuesta aparezcan:
+   - `Cache-Control: no-cache, no-store, must-revalidate, max-age=0`
+   - `Pragma: no-cache`
+   - `Expires: 0`
+
+## Nota Importante
+
+Estos cambios evitarán completamente el cache, lo que puede resultar en:
+- ✅ Actualizaciones inmediatas
+- ❌ Mayor uso de ancho de banda
+- ❌ Tiempos de carga ligeramente mayores
+
+Para producción, considera implementar cache selectivo solo en archivos que cambien frecuentemente.

+ 11 - 0
app.py

@@ -5,6 +5,7 @@ from config.settings import DEVELOPMENT, SECRET_KEY
 from routes import sales
 from services.email_service import initialize_email_sender
 from services.logging_service import structured_logger, LogLevel
+from middleware.no_cache import NoCacheMiddleware
 from logging import getLogger
 
 logger = getLogger(__name__)
@@ -82,6 +83,16 @@ def create_app() -> FastAPI:
             {"max_age_seconds": 3600}
         )
         
+        # Add NoCacheMiddleware
+        logger.info("Adding no-cache middleware")
+        app.add_middleware(NoCacheMiddleware)
+        
+        structured_logger.log_system_event(
+            "No-cache middleware configured",
+            LogLevel.INFO,
+            {"description": "Middleware for preventing cache on public files"}
+        )
+        
         logger.info("FastAPI application created successfully")
         return app
         

+ 6 - 0
middleware/__init__.py

@@ -0,0 +1,6 @@
+"""
+Middleware package
+"""
+from .no_cache import NoCacheMiddleware
+
+__all__ = ["NoCacheMiddleware"]

+ 39 - 0
middleware/no_cache.py

@@ -0,0 +1,39 @@
+"""
+Middleware para agregar headers de no-cache a las respuestas
+"""
+from starlette.middleware.base import BaseHTTPMiddleware
+from starlette.requests import Request
+from starlette.responses import Response
+
+
+class NoCacheMiddleware(BaseHTTPMiddleware):
+    """
+    Middleware que agrega headers de no-cache a todas las respuestas
+    que sirven archivos de la carpeta public
+    """
+    
+    async def dispatch(self, request: Request, call_next):
+        response = await call_next(request)
+        
+        # Lista de rutas que deben tener headers de no-cache
+        no_cache_paths = [
+            "/",
+            "/register",
+            "/verify",
+            "/express/",
+            "/register/",
+            "/images/"
+        ]
+        
+        # Verificar si la ruta actual debe tener headers de no-cache
+        should_no_cache = any(
+            request.url.path.startswith(path) for path in no_cache_paths
+        )
+        
+        if should_no_cache:
+            # Agregar headers de no-cache
+            response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate, max-age=0"
+            response.headers["Pragma"] = "no-cache"
+            response.headers["Expires"] = "0"
+        
+        return response

+ 6 - 0
public/main/index.html

@@ -4,6 +4,12 @@
   <meta charset="UTF-8" />
   <title>Biergarten Klein</title>
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  
+  <!-- Meta tags para evitar cache -->
+  <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
+  <meta http-equiv="Pragma" content="no-cache">
+  <meta http-equiv="Expires" content="0">
+  
   <!-- Fuentes + Tailwind -->
   <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
   <link rel="stylesheet" as="style" onload="this.rel='stylesheet'"

+ 6 - 0
public/register/index.html

@@ -4,6 +4,12 @@
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>Modal de Registro</title>
+    
+    <!-- Meta tags para evitar cache -->
+    <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
+    <meta http-equiv="Pragma" content="no-cache">
+    <meta http-equiv="Expires" content="0">
+    
     <script src="https://cdn.tailwindcss.com"></script>
     <script src="/register/app.js" defer></script>
 </head>

+ 6 - 0
public/verify.html

@@ -4,6 +4,12 @@
   <meta charset="UTF-8" />
   <title>Crear PIN - Biergarten Klein</title>
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  
+  <!-- Meta tags para evitar cache -->
+  <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
+  <meta http-equiv="Pragma" content="no-cache">
+  <meta http-equiv="Expires" content="0">
+  
   <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
   <link rel="stylesheet" as="style" onload="this.rel='stylesheet'"
         href="https://fonts.googleapis.com/css2?display=swap&family=Noto+Sans:wght@400;500;700;900&family=Spline+Sans:wght@400;500;700">

+ 43 - 5
routes/static.py

@@ -2,6 +2,23 @@ import os
 from fastapi import HTTPException
 from fastapi.responses import HTMLResponse, FileResponse
 from fastapi.staticfiles import StaticFiles
+from starlette.responses import Response
+from starlette.types import Scope, Receive, Send
+
+
+class NoCacheStaticFiles(StaticFiles):
+    """StaticFiles que agrega headers para evitar cache"""
+    
+    async def get_response(self, path: str, scope: Scope) -> Response:
+        """Override para agregar headers de no-cache"""
+        response = await super().get_response(path, scope)
+        
+        # Agregar headers para evitar cache
+        response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate, max-age=0"
+        response.headers["Pragma"] = "no-cache"
+        response.headers["Expires"] = "0"
+        
+        return response
 
 
 async def serve_app_html():
@@ -9,26 +26,47 @@ async def serve_app_html():
     index_path = os.path.join("public","main", "index.html")
     if not os.path.exists(index_path):
         raise HTTPException(status_code=404, detail="public/index.html not found.")
-    return FileResponse(index_path)
+    
+    # Headers para evitar cache
+    headers = {
+        "Cache-Control": "no-cache, no-store, must-revalidate, max-age=0",
+        "Pragma": "no-cache",
+        "Expires": "0"
+    }
+    return FileResponse(index_path, headers=headers)
 
 async def serve_register_html():
     """Serve the register HTML file"""
     register_path = os.path.join("public", "register", "index.html")
     if not os.path.exists(register_path):
         raise HTTPException(status_code=404, detail="public/register/index.html not found.")
-    return FileResponse(register_path)
+    
+    # Headers para evitar cache
+    headers = {
+        "Cache-Control": "no-cache, no-store, must-revalidate, max-age=0",
+        "Pragma": "no-cache",
+        "Expires": "0"
+    }
+    return FileResponse(register_path, headers=headers)
 
 def mount_register_static_files(app):
     """Mount static files for the register page"""
-    app.mount("/register/", StaticFiles(directory="public/register", html=False), name="register_static")
+    app.mount("/register/", NoCacheStaticFiles(directory="public/register", html=False), name="register_static")
 
 def mount_main_static_files(app):
     """Mount static files"""
-    app.mount("/express/", StaticFiles(directory="public/main", html=False), name="public_root_assets")
+    app.mount("/express/", NoCacheStaticFiles(directory="public/main", html=False), name="public_root_assets")
 
 def serve_image(image_path: str):
     """Serve images from the public/images directory"""
     image_full_path = os.path.join("public", "images", image_path)
     if not os.path.exists(image_full_path):
         raise HTTPException(status_code=404, detail=f"Image '{image_path}' not found.")
-    return FileResponse(image_full_path)
+    
+    # Headers para evitar cache en imágenes también
+    headers = {
+        "Cache-Control": "no-cache, no-store, must-revalidate, max-age=0",
+        "Pragma": "no-cache",
+        "Expires": "0"
+    }
+    return FileResponse(image_full_path, headers=headers)