Beyond Range Headers: Exploring Alternatives for Partial Data Requests in HTTP


  • Streaming media
    By requesting small chunks of a media file at a time, the client can start playing the media before the entire file is downloaded.
  • Resuming downloads
    If a download gets interrupted, the client can use the Range header to request the remaining part of the file.
  • Server-side
    The server interprets the Range header and responds accordingly:
    • If the server supports range requests and the request is valid, it will send a partial response with a status code of 206 (Partial Content). The response body will contain only the requested portion of the file.
    • If the server doesn't support range requests, it will typically send the entire file with a status code of 200 (OK).
    • If the requested range is invalid (e.g., out of bounds), the server may return an error code like 416 (Requested Range Not Satisfiable).
  • Client-side
    The client sets the Range header in the HTTP request message. The format of the header value specifies the part of the file being requested. There are different ways to define the range:
    • By byte range
      This specifies the starting and ending byte positions of the desired portion. For example, Range: bytes=1000-2000 would request bytes 1000 to 2000 (inclusive) of the file.
    • By suffix length
      This requests the last part of the file with a specified number of bytes. For example, Range: bytes=-1000 would request the last 1000 bytes of the file.

Here are some resources for further reading:

  • GeeksforGeeks on HTTP Range: [HTTP headers Range ON GeeksforGeeks geeksforgeeks.org]
  • MDN Web Docs on Range header: [MDN Range HTTP header]


Client-side (Python)

import requests

# Requesting the first 1000 bytes of a file
url = "https://example.com/large_file.txt"
headers = {"Range": "bytes=0-999"}

response = requests.get(url, headers=headers)

if response.status_code == 206:
  # Process the partial content in response.content
  print(f"Received first 1000 bytes of the file")
else:
  print(f"Error: {response.status_code}")
const express = require('express');
const fs = require('fs');

const app = express();

app.get('/file.mp4', (req, res) => {
  const range = req.headers.range;

  if (!range) {
    // Client didn't specify a Range header, send the whole file
    return res.sendFile('/path/to/file.mp4');
  }

  const videoStat = fs.statSync('/path/to/file.mp4');
  const fileSize = videoStat.size;

  const parts = range.replace(/bytes=/, "").split("-");
  const start = parseInt(parts[0], 10);
  const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1;

  if (isNaN(start) || isNaN(end) || start >= fileSize || end >= fileSize) {
    // Invalid range request
    return res.status(416).send("Requested range not satisfiable");
  }

  const contentLength = end - start + 1;
  const head = {
    "Content-Range": `bytes ${start}-${end}/${fileSize}`,
    "Accept-Ranges": "bytes",
    "Content-Length": contentLength,
    "Content-Type": "video/mp4",
  };

  res.status(206).writeHead(head);
  fs.createReadStream('/path/to/file.mp4', { start, end }).pipe(res);
});

app.listen(3000, () => console.log('Server listening on port 3000'));


  1. Query String Parameters

This approach involves adding parameters to the URL that specify the desired portion of data. For example, for pagination:

  • /data?page=2&size=10 - This would request the second page with 10 items.

This is simpler than the Range header, but it's not as standardized and may not be ideal for all scenarios.

  1. Content-Disposition Header

This header, typically used for downloads, can be used to suggest a filename for the downloaded content. While not directly requesting a specific portion, it can be helpful when combined with other methods like query string parameters. For example, with pagination:

  • Downloading page 2 of a document might be triggered with /document?page=2 and the server might respond with a Content-Disposition: attachment; filename=document-page-2.pdf header.
  1. Custom Headers

If none of the standard options fit your needs, you can define custom headers specific to your application. This allows for more flexibility but requires agreement between the client and server on the meaning and format of the header.

  1. Server-Side Logic

For specific use cases, you might consider implementing server-side logic that identifies the requested portion based on other information in the request. For example, an API endpoint might accept an ID in the URL and internally retrieve only the relevant data for that specific item.