The HTTP 206 Partial Content status code indicates successful fulfillment of a range request. When clients request specific portions of a resource (like video files), servers respond with:
HTTP/1.1 206 Partial Content
Content-Range: bytes 0-999/123456
Content-Length: 1000
This mechanism allows efficient media streaming without downloading entire files upfront.
Modern video players (including Video.js) intelligently request only needed portions:
- Initial metadata (first few KB)
- Buffered chunks during playback
- Seek positions when users jump
// Sample Range header from Chrome
Range: bytes=0-1023
To confirm actual data transfer:
# Apache access log analysis
awk '$9 == 206 {sum += $10} END {print sum}' access_log
This sums all 206 response bytes. Compare with:
# Full file requests
awk '$9 == 200 {sum += $10} END {print sum}' access_log
Apache configuration best practices:
<IfModule mod_headers.c>
# Enable byte-range support
Header set Accept-Ranges bytes
# Cache partial content
<FilesMatch "\.(mp4|webm)$">
Header set Cache-Control "max-age=31536000, public"
</FilesMatch>
</IfModule>
Modern players automatically manage range requests. Example initialization:
videojs('my-video', {
techOrder: ['html5'],
html5: {
nativeTextTracks: false,
nativeControlsForTouch: false
}
});
To verify behavior in browser dev tools:
- Open Network panel
- Filter by "media" type
- Check response status and Content-Range headers
For cellular networks, consider:
- Lower default bitrate (use Video.js quality selector)
- Smaller initial buffer window
- CDN delivery with HTTP/2
// Adaptive bitrate configuration
videojs.Hls.defaultOptions = {
bandwidth: 800000, // 800kbps initial estimate
abrEwmaDefaultEstimate: 500000 // conservative mobile default
};
When your browser requests video files, it doesn't necessarily download the entire file at once. The HTTP 206 Partial Content response indicates successful range requests - a crucial optimization technique for media streaming. Your Apache logs show exactly this behavior:
GET /videos/a_video.mp4 HTTP/1.1\" 206 1130496
Modern browsers send Range
headers to request specific portions of a file. For video.js implementations, this typically looks like:
GET /videos/sample.mp4 HTTP/1.1
Host: example.com
Range: bytes=0-1048575
The server responds with the requested byte range and 206 status:
HTTP/1.1 206 Partial Content
Content-Range: bytes 0-1048575/5242880
Content-Length: 1048576
Content-Type: video/mp4
The 1.1MB transfer in your logs represents just the initial buffer needed to start playback. Video.js (and most modern players) will:
- Request small initial chunks to minimize startup latency
- Progressively download additional ranges as needed
- Support seeking by requesting specific byte ranges
Ensure your Apache server properly handles range requests with these directives:
<IfModule mod_headers.c>
Header set Accept-Ranges bytes
</IfModule>
<IfModule mod_deflate.c>
<IfModule mod_filter.c>
SetOutputFilter DEFLATE
# Exclude binary files from compression
SetEnvIfNoCase Request_URI \.(?:mp4|mov|avi)$ no-gzip
</IfModule>
</IfModule>
Verify your server's range support using curl:
curl -I -H "Range: bytes=0-100" http://yoursite.com/video.mp4
Look for these headers in the response:
HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Content-Range: bytes 0-100/1234567
The 206 responses you're seeing are actually optimal for bandwidth usage:
- Mobile clients receive only what they need for immediate playback
- Users who close the modal before finishing won't download the entire file
- Seeking becomes more efficient as clients request only new ranges
For large video libraries, consider adding these Apache optimizations:
# Enable sendfile for efficient file transfers
EnableSendfile on
# Set appropriate cache headers for media files
<FilesMatch "\.(mp4|mov)$">
Header set Cache-Control "max-age=604800, public"
</FilesMatch>