TIdHttpServer响应HTTP GET发送文件片段,多连接分段下载遇阻
我正在开发一款小型Web服务器,希望支持下载管理器通过多连接同时分段下载大文件。目前已经能通过ARequestInfo.Ranges属性检测到下载管理器的分段下载请求,还编写了自定义TFileFragmentStream类,以TStream子类的形式提供指定范围的文件片段。但下载管理器似乎不认可服务器支持该功能,仍然只用单连接下载——不过我能看到它发起了分段请求,推测是响应的设置没满足要求。
我当前的初始实现代码如下:
PROCEDURE SendPartialFile(Response : TIdHttpResponseInfo ; CONST N : TFileName ; RangeStart,RangeEnd : Int64); BEGIN Response.ContentType:='application/octet-stream'; Response.ContentDisposition:='attachment; filename="'+ExrractFileName(N)+'"'; Response.ContentLength:=SUCC(RangeEnd-RangeStart); Response.ContentStream:=TFileFragmentStream.Create(N,RangeStart,ContentLength) Response.FreeContentStream:=TRUE END;
请问还需要设置响应的哪些属性?
最终更新代码:
ContentDisposition:='attachment; filename="'+N.NameOnly+'"'; VAR S:=TIdHTTPRangeStream.Create(TFileStream.Create(N,fmOpenRead OR fmShareDenyNone),RangeStart,RangeEnd); ContentStream:=S; ResponseNo:=S.ResponseCode; ContentRangeStart:=S.RangeStart; ContentRangeEnd:=S.RangeEnd; ContentText:=''; ContentRangeInstanceLength:=S.SourceStream.Size; OutputDebugString('Sending File Fragment: '+ContentType+' ['+IntToStr(ContentRangeStart)+'-'+IntToStr(ContentRangeEnd)+'] ('+IntToStr(ContentLength)+' bytes) "'+ContentDisposition+'" ResponseNo='+IntToStr(ResponseNo)); FreeContentStream:=TRUE;
日志信息如下:
Sending Full File: video/mp4 XX.mp4 (6573584385 bytes) Sending File Fragment: video/mp4 [233600-6573584384] (6573350785 bytes) "attachment; filename="XX.mp4"" ResponseNo=206 Sending File Fragment: video/mp4 [3286914832-6573584384] (3286669553 bytes) "attachment; filename="XX.mp4"" ResponseNo=206 Sending File Fragment: video/mp4 [4930249645-6573584384] (1643334740 bytes) "attachment; filename="XX.mp4"" ResponseNo=206 Sending File Fragment: video/mp4 [1655659767-3286914895] (1631255129 bytes) "attachment; filename="XX.mp4"" ResponseNo=206 Sending File Fragment: video/mp4 [4108582275-4930249708] (821667434 bytes) "attachment; filename="XX.mp4"" ResponseNo=206 Sending File Fragment: video/mp4 [5751917052-6573584384] (821667333 bytes) "attachment; filename="XX.mp4"" ResponseNo=206 Sending File Fragment: video/mp4 [2471287336-3286914895] (815627560 bytes) "attachment; filename="XX.mp4"" ResponseNo=206 Sending File Fragment: video/mp4 [855370091-1655659830] (800289740 bytes) "attachment; filename="XX.mp4"" ResponseNo=206
完整文件的处理代码如下:
ContentType:='application/octet-stream' ContentDisposition:='attachment; filename="'+ExtractFileName(FileName)+'"' ContentStream:=TFileStream.Create(FileName,fmOpenRead OR fmShareDenyNone) FreeContentStream:=TRUE ResponseNo:=200
问题分析与解决要点
设置正确的响应状态码
分段下载请求的响应必须返回206 Partial Content状态码,而非默认的200。初始代码未设置Response.ResponseNo,客户端会误认为服务器不支持范围请求,因此不会启用多连接下载。完善Content-Range相关属性
除ContentLength外,还需明确告知客户端当前片段的范围和文件总大小:ContentRangeStart:当前片段的起始字节位置ContentRangeEnd:当前片段的结束字节位置ContentRangeInstanceLength:整个文件的总字节数
这些属性会组装成Content-Range响应头,是客户端识别分段内容的核心依据。
主动声明支持范围请求
在处理完整文件请求(响应码200)时,需添加Accept-Ranges: bytes响应头,主动告知客户端服务器支持分段下载,这样下载管理器才会尝试发起多连接分段请求。可在完整文件处理代码中补充:Response.AcceptRanges := 'bytes';修复代码拼写错误
初始代码中的ExrractFileName是拼写错误,应改为ExtractFileName,否则会导致文件名解析错误,影响下载后的文件名正确性。
从你提供的最终代码和日志来看,改用TIdHTTPRangeStream后已自动处理了响应码和ContentRange相关属性,日志中也显示多个206响应的分段请求,说明服务器已正确支持多连接分段下载。
内容的提问来源于stack exchange,提问作者HeartWare

