delphi INDY:发送文件片段作为对TIdHttpServer.OnCommandGet中HTTPGET命令的响应

0qx6xfy6  于 2023-06-29  发布在  其他
关注(0)|答案(1)|浏览(132)

我正在开发一个小型的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;

我的Response是否还有其他属性需要设置?
更新最终代码:

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
2ledvvac

2ledvvac1#

您需要设置各种AResponseInfo.ContentRange...属性来描述实际发送回客户端的范围:

ContentRangeStart
ContentRangeEnd
ContentRangeInstanceLength
ContentRangeUnits

此外,请确保您正在设置AResponseInfo.ResponseNo,以指示您是发送部分范围(206)还是发送完整文件(200)。
阅读RFC 2616第10.2.7 206节部分内容和第14.16节内容范围以了解更多详细信息。
顺便说一句,TIdHTTPServer有自己的TIdHTTPRangeStream助手类,用于发送源TStream的部分范围。您可以使用源流(例如TFileStream)和请求的范围构建它,然后使用其ResponseCodeRangeStartRangeEnd属性来更新AResponseInfo,例如:

Procedure SendPartialFile(Response: TIdHTTPResponseInfo; const FileName: TFileName; RangeStart, RangeEnd: Int64);
begin   
  Response.ContentType := 'application/octet-stream';
  Response.ContentDisposition := 'attachment; filename="'+ExtractFileName(FileName)+'"';
  Response.ContentStream := TIdHTTPRangeStream.Create(TIdReadFileExclusiveStream.Create(FileName), RangeStart, RangeEnd);
  Response.FreeContentStream := True;
  Response.ResponseNo := TIdHTTPRangeStream(Response.ContentStream).ResponseCode;
  if Response.ResponseNo = 206 then
  begin
    Response.ContentRangeStart := TIdHTTPRangeStream(Response.ContentStream).RangeStart;
    Response.ContentRangeEnd := TIdHTTPRangeStream(Response.ContentStream).RangeEnd;
    Response.ContentRangeInstanceLength := TIdHTTPRangeStream(Response.ContentStream).SourceStream.Size;
  end;
end;

相关问题