Skip to content

Latest commit

 

History

History
182 lines (134 loc) · 4.58 KB

File metadata and controls

182 lines (134 loc) · 4.58 KB

HTTP Caching Debug Analysis

Observed Behavior

127.0.0.1 - - [17/Nov/2025 16:03:28] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [17/Nov/2025 16:03:39] "GET / HTTP/1.1" 304 -
127.0.0.1 - - [17/Nov/2025 16:04:15] "GET / HTTP/1.1" 304 -
  • First request: Returns 200 (OK) - Full response sent
  • Subsequent requests: Return 304 (Not Modified) - Browser uses cached version

What's Happening

Flask's send_from_directory() automatically implements HTTP caching using:

  1. ETag Header: A hash/fingerprint of the file content

    • Browser sends If-None-Match header with the ETag
    • Server compares, returns 304 if file unchanged
  2. Last-Modified Header: File's last modification timestamp

    • Browser sends If-Modified-Since header
    • Server compares, returns 304 if file not modified

Current Server Implementation

In Dashboard/server.py:

@app.route('/')
def index():
    """Serve the main dashboard"""
    return send_from_directory('.', 'dashboard.html')

Flask's send_from_directory() automatically adds:

  • ETag header (content hash)
  • Last-Modified header (file mtime)
  • Cache-Control header (default: public)

Why This Happens

Request Flow:

  1. First Request:

    GET / HTTP/1.1
    Host: localhost:8000
    

    Response:

    HTTP/1.1 200 OK
    ETag: "abc123"
    Last-Modified: Mon, 17 Nov 2025 16:00:00 GMT
    Content-Length: 12345
    [full content]
    
  2. Second Request (browser includes caching headers):

    GET / HTTP/1.1
    Host: localhost:8000
    If-None-Match: "abc123"
    If-Modified-Since: Mon, 17 Nov 2025 16:00:00 GMT
    

    Response:

    HTTP/1.1 304 Not Modified
    ETag: "abc123"
    Last-Modified: Mon, 17 Nov 2025 16:00:00 GMT
    [no body - browser uses cache]
    

Is This a Problem?

No - This is the correct and expected behavior for static file serving:

Benefits:

  • Reduces bandwidth usage
  • Faster page loads (no content transfer)
  • Less server processing
  • Better user experience

⚠️ Only a problem if:

  • You're actively developing and want fresh content every time
  • You need to bypass cache for testing
  • Users need to see updates immediately

Solutions

Option 1: Disable Caching (Development Only)

Add cache control headers to prevent caching:

from flask import Flask, send_from_directory, make_response

@app.route('/')
def index():
    """Serve the main dashboard"""
    response = make_response(send_from_directory('.', 'dashboard.html'))
    response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'
    response.headers['Pragma'] = 'no-cache'
    response.headers['Expires'] = '0'
    return response

Option 2: Hard Refresh in Browser

Force browser to fetch fresh content:

  • Chrome/Firefox: Ctrl + Shift + R or Cmd + Shift + R (Mac)
  • All browsers: Ctrl + F5

Option 3: Conditional Caching

Enable caching in production, disable in development:

@app.route('/')
def index():
    """Serve the main dashboard"""
    response = make_response(send_from_directory('.', 'dashboard.html'))

    # Disable caching in debug mode
    if app.debug:
        response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'
    else:
        # Allow caching in production (default Flask behavior)
        response.headers['Cache-Control'] = 'public, max-age=300'  # 5 minutes

    return response

Option 4: Version-Based Caching

Add version parameter to URLs:

<!-- In dashboard.html -->
<script src="script.js?v=1.2.3"></script>
<link rel="stylesheet" href="style.css?v=1.2.3">

Changing the version forces browser to fetch new file.

Testing Caching Behavior

Use the provided test script:

python3 test_caching.py

Or use curl to inspect headers:

# First request
curl -I http://localhost:8000/

# Conditional request (should get 304)
ETAG=$(curl -s -I http://localhost:8000/ | grep -i etag | cut -d' ' -f2)
curl -I -H "If-None-Match: $ETAG" http://localhost:8000/

Recommendations

  1. For Production: Keep caching enabled (current behavior is optimal)

  2. For Development:

    • Use --debug flag when starting server
    • Use hard refresh in browser
    • Or disable caching for development mode
  3. For Active Development: Add --no-cache flag option to server.py

References