← 中文资源

简体中文版本

HTTP Range 头解析(JavaScript)

解析单段 HTTP Range 头,结合资源大小把开放式区间解析为可满足的字节范围。

阅读英文原文

功能说明

该示例解析下载与视频播放常用的 Range 请求头,只处理规范允许的单段形式 bytes=start-end。它区分三种写法:普通区间、开放结尾,以及从末尾计数的后缀形式。解析结果包含起始、结束字节与长度,或以 unsatisfiable 标记该范围不可满足。

关键代码

正则同时捕获两段,允许任一端为空以表达开放或后缀。后缀形式里 0 是非法的,单独处理。结尾为空时取资源最后一个字节;随后统一检查起点是否大于终点、起点是否越界,并对终点做上界截断。长度计算用截断后的终点,避免返回超出资源的长度。输入缺失时返回 null 表示没有范围请求,与不可满足区分开。

使用注意

多段范围在真实请求中少见且实现复杂,本示例明确只支持单段,遇到不匹配即视为不可满足,调用方应回以 416 与 Content-Range 头说明当前长度。资源大小为 0 时任何范围都不可满足。解析器不处理 If-Range 条件,需要时应先校验 ETag 或日期再决定是否回退为完整响应,否则可能向已变动的资源返回过期字节。

代码示例

export function parseRange(header, size) {
  if (!header || typeof header !== 'string') return null;
  const match = /^bytes=(\d*)-(\d*)$/.exec(header.trim());
  if (!match) return { unsatisfiable: true };
  const [, startRaw, endRaw] = match;
  if (startRaw === '' && endRaw === '') return { unsatisfiable: true };
  let start;
  let end;
  if (startRaw === '') {
    const suffix = Number(endRaw);
    if (suffix === 0) return { unsatisfiable: true };
    start = Math.max(size - suffix, 0);
    end = size - 1;
  } else {
    start = Number(startRaw);
    end = endRaw === '' ? size - 1 : Number(endRaw);
  }
  if (start > end || start >= size) return { unsatisfiable: true };
  return { start, end: Math.min(end, size - 1), length: Math.min(end, size - 1) - start + 1 };
}