- Home
- HTTP Headers
- Accept-Ranges Header
Header
Accept-Ranges Header
Learn how the Accept-Ranges header tells clients whether your server supports partial content requests (byte ranges) for efficient downloads and streaming.
TL;DR: Tells clients whether the server supports partial content requests (byte ranges). Enables resume downloads, video seeking, and efficient large file transfers.
What is Accept-Ranges?
The Accept-Ranges header tells clients whether the server supports partial content requests. It’s like a server saying “Yes, you can download this file in chunks” or “No, you must download the whole thing at once.”
This enables features like pause/resume downloads, video seeking, and efficient large file transfers.
How Accept-Ranges Works
Server indicates range support:
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 10485760
Content-Type: video/mp4
[video content]
```text
**Client can then request partial content:**
```http
GET /video.mp4 HTTP/1.1
Host: cdn.example.com
Range: bytes=0-1048575
Server responds with partial content:
HTTP/1.1 206 Partial Content
Content-Range: bytes 0-1048575/10485760
Content-Length: 1048576
Accept-Ranges: bytes
[first 1MB of video]
```http
## Syntax
```http
Accept-Ranges: bytes
Accept-Ranges: none
Values
- bytes - Server supports byte-range requests
- none - Server does not support range requests
Common Examples
Supporting Range Requests
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Type: application/pdf
Content-Length: 5242880
```text
Server supports byte ranges for the PDF file.
### Not Supporting Range Requests
```http
HTTP/1.1 200 OK
Accept-Ranges: none
Content-Type: text/html
Server requires the entire resource to be downloaded.
Streaming Video
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Type: video/mp4
Content-Length: 104857600
```text
Video can be streamed and seeked because byte ranges are supported.
## Real-World Scenarios
### Video Streaming Platform
```http
# Initial request
GET /videos/movie.mp4 HTTP/1.1
Host: streaming.example.com
# Server response
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Type: video/mp4
Content-Length: 524288000
# Client seeks to 5 minutes in
GET /videos/movie.mp4 HTTP/1.1
Host: streaming.example.com
Range: bytes=15728640-20971519
# Server sends that chunk
HTTP/1.1 206 Partial Content
Content-Range: bytes 15728640-20971519/524288000
Accept-Ranges: bytes
Download Manager with Resume
# Download interrupted at 50%
GET /large-file.zip HTTP/1.1
Host: downloads.example.com
Range: bytes=52428800-
# Server resumes from that point
HTTP/1.1 206 Partial Content
Content-Range: bytes 52428800-104857599/104857600
Accept-Ranges: bytes
Content-Length: 52428800
```text
### PDF Viewer Progressive Loading
```http
# Load first page quickly
GET /document.pdf HTTP/1.1
Host: docs.example.com
Range: bytes=0-102399
HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Content-Range: bytes 0-102399/2097152
Server Implementation
Express.js (Node.js)
const express = require('express')
const fs = require('fs')
const app = express()
app.get('/video/:id', (req, res) => {
const videoPath = `./videos/${req.params.id}.mp4`
const stat = fs.statSync(videoPath)
const fileSize = stat.size
const range = req.headers.range
// Always indicate range support
res.setHeader('Accept-Ranges', 'bytes')
if (range) {
const parts = range.replace(/bytes=/, '').split('-')
const start = parseInt(parts[0], 10)
const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1
const chunkSize = end - start + 1
const file = fs.createReadStream(videoPath, { start, end })
res.status(206)
res.setHeader('Content-Range', `bytes ${start}-${end}/${fileSize}`)
res.setHeader('Content-Length', chunkSize)
res.setHeader('Content-Type', 'video/mp4')
file.pipe(res)
} else {
res.setHeader('Content-Length', fileSize)
res.setHeader('Content-Type', 'video/mp4')
fs.createReadStream(videoPath).pipe(res)
}
})
```nginx
### Nginx Configuration
```nginx
server {
listen 80;
server_name cdn.example.com;
location /videos/ {
# Nginx automatically adds Accept-Ranges: bytes
# and handles range requests for static files
root /var/www;
}
location /api/ {
# Disable range requests for API endpoints
add_header Accept-Ranges none;
proxy_pass http://backend;
}
}
Python (Flask)
from flask import Flask, request, send_file, Response
import os
app = Flask(__name__)
@app.route('/download/<filename>')
def download_file(filename):
file_path = f'./files/{filename}'
file_size = os.path.getsize(file_path)
range_header = request.headers.get('Range')
if range_header:
byte_range = range_header.replace('bytes=', '').split('-')
start = int(byte_range[0])
end = int(byte_range[1]) if byte_range[1] else file_size - 1
with open(file_path, 'rb') as f:
f.seek(start)
data = f.read(end - start + 1)
response = Response(data, 206, mimetype='application/octet-stream')
response.headers.add('Content-Range', f'bytes {start}-{end}/{file_size}')
response.headers.add('Accept-Ranges', 'bytes')
response.headers.add('Content-Length', len(data))
return response
else:
response = send_file(file_path)
response.headers.add('Accept-Ranges', 'bytes')
return response
```text
## Best Practices
### For Servers
**1. Enable range support for large files**
```http
# ✅ Good for videos, downloads, large PDFs
Accept-Ranges: bytes
# ❌ Avoid for dynamic content
Accept-Ranges: none
2. Always include Accept-Ranges header
// Even when not supporting ranges, be explicit
res.setHeader('Accept-Ranges', 'none')
```javascript
**3. Validate range requests**
```javascript
if (range) {
const parts = range.replace(/bytes=/, '').split('-')
const start = parseInt(parts[0], 10)
const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1
// Validate ranges
if (start >= fileSize || end >= fileSize || start > end) {
return res.status(416).send('Range Not Satisfiable')
}
}
4. Set proper cache headers
Accept-Ranges: bytes
ETag: "abc123"
Cache-Control: public, max-age=3600
```text
### For Clients
**1. Check for range support before requesting ranges**
```javascript
// First, check if server supports ranges
fetch('/video.mp4', { method: 'HEAD' }).then((res) => {
if (res.headers.get('Accept-Ranges') === 'bytes') {
// Safe to request ranges
return fetch('/video.mp4', {
headers: { Range: 'bytes=0-1048575' }
})
}
})
2. Handle both 200 and 206 responses
fetch('/file.zip', {
headers: { Range: 'bytes=1000000-' }
}).then((res) => {
if (res.status === 206) {
// Partial content received
console.log('Resuming download')
} else if (res.status === 200) {
// Full content (server doesn't support ranges)
console.log('Downloading full file')
}
})
```text
## Common Use Cases
### Video Players
```http
Accept-Ranges: bytes
Allows seeking to any point in the video without downloading the entire file.
Download Managers
Accept-Ranges: bytes
```text
Enables pause/resume functionality and parallel chunk downloads.
### PDF Viewers
```http
Accept-Ranges: bytes
Progressive loading of large documents for better user experience.
CDN Distribution
Accept-Ranges: bytes
```text
Efficient distribution of large files across network segments.
## When to Disable Range Requests
### Dynamic Content
```http
Accept-Ranges: none
Content generated on-the-fly that can’t be easily chunked.
Compressed Responses
Accept-Ranges: none
Content-Encoding: gzip
```text
Gzipped content typically shouldn't support ranges.
### Security-Sensitive Content
```http
Accept-Ranges: none
When partial access could expose sensitive information.
Testing Accept-Ranges
Using curl
# Check if ranges are supported
curl -I https://cdn.example.com/video.mp4
# Request first 1000 bytes
curl -H "Range: bytes=0-999" https://cdn.example.com/video.mp4
# Request from byte 1000 to end
curl -H "Range: bytes=1000-" https://cdn.example.com/video.mp4
# Request last 1000 bytes
curl -H "Range: bytes=-1000" https://cdn.example.com/video.mp4
```javascript
### Using JavaScript
```javascript
// Check range support
const response = await fetch('/video.mp4', { method: 'HEAD' })
console.log(response.headers.get('Accept-Ranges'))
// Request partial content
const partial = await fetch('/video.mp4', {
headers: {
Range: 'bytes=0-1048575'
}
})
console.log(partial.status) // Should be 206 if supported
Related Headers
- Range - Client requests specific byte ranges
- Content-Range - Server indicates which bytes are being sent
- Content-Length - Total size of the content
- ETag - Resource version for conditional range requests
Frequently Asked Questions
What is Accept-Ranges?
Accept-Ranges indicates whether the server supports range requests. "bytes" means ranges are supported; "none" means they are not. Absence implies possible support.
Why is Accept-Ranges important?
It tells clients if they can resume downloads or request partial content. Video players and download managers check this before attempting range requests.
What does Accept-Ranges: none mean?
The server explicitly does not support range requests. Clients should not send Range headers and must download the complete resource.
How do I enable Accept-Ranges on my server?
Most servers enable it by default for static files. For dynamic content, you must implement range handling in your application code and set the header explicitly.