You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在TIdHTTPServer中处理GET请求实现浏览器视频拖拽定位?

实现支持进度拖拽的MP4 HTTP服务器(基于IdHTTPServer)

问题描述

使用Delphi的IdHTTPServer实现了简易HTTP服务器,可完整播放MP4视频,但无法支持浏览器中的进度跳转功能。当前核心代码如下:

...
AResponseInfo.ContentStream := TFileStream.Create('MyVideo.mp4', fmOpenRead or fmShareCompat);
...

解决方案:支持HTTP Range请求

浏览器调整播放进度时,会向服务器发送包含Range字段的请求,要求获取文件的指定片段。服务器需要解析该请求并返回对应的文件部分,同时设置正确的响应头。

具体实现逻辑

  • 检查请求头中是否存在Range字段
  • 解析Range格式,提取起始偏移量和结束偏移量
  • 修正超出文件范围的偏移值,计算要发送的内容长度
  • 设置响应状态码为206 Partial Content,并填充Content-Range、Accept-Ranges等关键响应头
  • 打开文件流,定位到起始偏移位置,读取指定长度的内容返回

完整代码示例

procedure TForm1.IdHTTPServer1CommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
  VideoPath: string;
  FileSize: Int64;
  StartPos, EndPos, SendSize: Int64;
  RangeStr: string;
  FileStream: TFileStream;
  ContentStream: TMemoryStream;
begin
  VideoPath := 'MyVideo.mp4';
  if not FileExists(VideoPath) then
  begin
    AResponseInfo.ResponseNo := 404;
    Exit;
  end;

  FileSize := TFile.GetSize(VideoPath);
  AResponseInfo.AcceptRanges := 'bytes';
  AResponseInfo.ContentType := 'video/mp4';

  // 处理Range分段请求
  RangeStr := ARequestInfo.Ranges.Text;
  if RangeStr <> '' then
  begin
    if Pos('bytes=', RangeStr) = 1 then
    begin
      Delete(RangeStr, 1, 6);
      // 解析起始偏移
      StartPos := StrToIntDef(Copy(RangeStr, 1, Pos('-', RangeStr)-1), 0);
      // 解析结束偏移,默认到文件末尾
      EndPos := StrToIntDef(Copy(RangeStr, Pos('-', RangeStr)+1, MaxInt), FileSize-1);

      // 校验偏移合法性
      if StartPos >= FileSize then
      begin
        AResponseInfo.ResponseNo := 416; // 请求范围无效
        AResponseInfo.ContentText := 'Requested range not satisfiable';
        Exit;
      end;
      if EndPos >= FileSize then
        EndPos := FileSize - 1;

      SendSize := EndPos - StartPos + 1;
      AResponseInfo.ResponseNo := 206; // 返回部分内容
      AResponseInfo.ContentRange := Format('bytes %d-%d/%d', [StartPos, EndPos, FileSize]);
      AResponseInfo.ContentLength := SendSize;

      // 读取指定范围的文件内容
      FileStream := TFileStream.Create(VideoPath, fmOpenRead or fmShareCompat);
      try
        FileStream.Position := StartPos;
        ContentStream := TMemoryStream.Create;
        try
          ContentStream.CopyFrom(FileStream, SendSize);
          AResponseInfo.ContentStream := ContentStream;
        except
          ContentStream.Free;
          raise;
        end;
      finally
        FileStream.Free;
      end;
    end;
  end
  else
  begin
    // 无Range请求,返回完整文件
    AResponseInfo.ResponseNo := 200;
    AResponseInfo.ContentLength := FileSize;
    AResponseInfo.ContentStream := TFileStream.Create(VideoPath, fmOpenRead or fmShareCompat);
  end;
end;

关键说明

  • Accept-Ranges: bytes:告知客户端服务器支持字节范围请求
  • 206 Partial Content:明确返回的是文件的部分内容
  • Content-Range:指定返回内容的字节区间和文件总大小,帮助浏览器定位播放进度
  • 必须处理超出文件范围的请求,返回416状态码避免客户端报错

内容的提问来源于stack exchange,提问作者Alex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 07:52:42