针对MS Graph API的Indy TIdHttp put命令的内容范围问题



我试图使用TIdHttp.Put()为微软的图形API,但它是不可能使用Content-Range头。如果我使用Ranges属性,然后我得到一个关于缺失的Content-Range的错误,如果我在CustomHeaders属性中使用这个头,然后我得到一个关于无效的Content-Range的错误。

代码如下:

sUploadSession := jsnUSession.Get('uploadUrl').JsonValue.Value;
Form1.htp2.Request.ContentType := 'application/octet-stream';
Form1.htp2.Request.ContentLength := iSize;          //  3820753
Form1.htp2.Request.CustomHeaders.Clear;
//Form1.htp.Request.CustomHeaders.Add('Content-Length: ' + IntToStr(iSize));
Form1.htp2.Request.CustomHeaders.Add('Content-Range: bytes 0-' + IntToStr(iSize - 1) + '/' + IntToStr(iSize));   //  'Content-Range: bytes 0-3820750/3820751'
{with Form1.htp2.Request.Ranges.Add do
begin
StartPos := 0;
EndPos := iSize;
s := Text; 
end;   }
fs := TStringStream.Create('{' + TEncoding.Default.GetString(TFile.ReadAllBytes(sFile)) + '}');
bLog := True;
try
Form1.htp2.Put(sUploadSession, fs);
except
on E: EIdHTTPProtocolException do
Form1.RichEdit1.Lines.Add(E.Message + #13#10 + E.ErrorMessage);
end;

当我使用Ranges属性的消息是:

HTTP/1.1 400 Bad Request
{"error":{"code":"MissingContentRangeHeader","message":"Content-Range header is required."}}

CustomHeadersContent-Range的消息为:

HTTP/1.1 400 Bad Request
{"error":{"code":"InvalidContentRangeHeader","message":"Invalid Content-Range header."}}

Indy中的PUT命令是否与HTTP中的标准兼容,或者是否需要进行调整以使其工作?

RangeContent-RangeHTTP头是两个完全不同的东西。看到内容范围和范围标头之间的区别?

Content-Range用于指定包含Content-Range报头的同一消息正文中的字节范围。

Range报头用于从服务器请求一个字节范围。响应消息将通过其自己的Content-Range指示在响应体中发送的实际范围。

所以,这就解释了为什么你会得到一个"缺失的Content-Range"使用TIdHTTP.Ranges属性时出现错误。

至于使用TIdHTTP.Request.CustomHeaders属性发送Content-Range头,这是正确的方法(从技术上讲,TIdEntityHeaderInfo具有ContentRange...属性,但它们目前仅由TIdHTTP.Response使用,而不是TIdHTTP.Request-这需要修复)。

您的自定义Content-Range头的问题是,服务器只是拒绝它作为坏。这很可能意味着您正在使用的iSize值实际上与您实际发送的字节数不匹配。

试试这样写:

sUploadSession := jsnUSession.Get('uploadUrl').JsonValue.Value;
fs := TStringStream.Create('{' + TEncoding.Default.GetString(TFile.ReadAllBytes(sFile)) + '}');
try
bLog := True;
try
iSize := fs.Size; // <-- the TStringStream constructor internally converted the String to TBytes...
Form1.htp2.Request.ContentType := 'application/octet-stream';
Form1.htp2.Request.ContentLength := iSize;
Form1.htp2.Request.CustomHeaders.Clear;
Form1.htp2.Request.CustomHeaders.Add('Content-Range: bytes 0-' + IntToStr(iSize - 1) + '/' + IntToStr(iSize));
Form1.htp2.Put(sUploadSession, fs);
except
on E: EIdHTTPProtocolException do
Form1.RichEdit1.Lines.Add(E.Message + #13#10 + E.ErrorMessage);
end;
finally
fs.Free;
end;

然而,没有很好的理由将文件读取为解码的UTF-16string只是为了将其转换回字节进行传输,所以只需按原样发送原始文件字节,例如:

sUploadSession := jsnUSession.Get('uploadUrl').JsonValue.Value;
fs := TFileStream.Create(sFile, fmOpenRead or fmShareDenyWrite);
try
bLog := True;
try
iSize := fs.Size;
Form1.htp2.Request.ContentType := 'application/octet-stream';
Form1.htp2.Request.ContentLength := iSize;
Form1.htp2.Request.CustomHeaders.Clear;
Form1.htp2.Request.CustomHeaders.Add('Content-Range: bytes 0-' + IntToStr(iSize - 1) + '/' + IntToStr(iSize));
Form1.htp2.Put(sUploadSession, fs);
except
on E: EIdHTTPProtocolException do
Form1.RichEdit1.Lines.Add(E.Message + #13#10 + E.ErrorMessage);
end;
finally
fs.Free;
end;

另外:

sUploadSession := jsnUSession.Get('uploadUrl').JsonValue.Value;
fs := TBytesStream.Create(TFile.ReadAllBytes(sFile));
try
bLog := True;
try
iSize := fs.Size;
Form1.htp2.Request.ContentType := 'application/octet-stream';
Form1.htp2.Request.ContentLength := iSize;
Form1.htp2.Request.CustomHeaders.Clear;
Form1.htp2.Request.CustomHeaders.Add('Content-Range: bytes 0-' + IntToStr(iSize - 1) + '/' + IntToStr(iSize));
Form1.htp2.Put(sUploadSession, fs);
except
on E: EIdHTTPProtocolException do
Form1.RichEdit1.Lines.Add(E.Message + #13#10 + E.ErrorMessage);
end;
finally
fs.Free;
end;

另外:

sUploadSession := jsnUSession.Get('uploadUrl').JsonValue.Value;
fs := TMemoryStream.Create;
try
bLog := True;
try
fs.LoadFromFile(sFile);
fs.Position := 0;
iSize := fs.Size;
Form1.htp2.Request.ContentType := 'application/octet-stream';
Form1.htp2.Request.ContentLength := iSize;
Form1.htp2.Request.CustomHeaders.Clear;
Form1.htp2.Request.CustomHeaders.Add('Content-Range: bytes 0-' + IntToStr(iSize - 1) + '/' + IntToStr(iSize));
Form1.htp2.Put(sUploadSession, fs);
except
on E: EIdHTTPProtocolException do
Form1.RichEdit1.Lines.Add(E.Message + #13#10 + E.ErrorMessage);
end;
finally
fs.Free;
end;

无论哪种方式,请注意Microsoft建议在使用此PUTAPI时一次上传不超过4MB。您的示例文件是3.6MB,因此它只适合单个PUT请求,但要知道,对于更大的文件,您将不得不将它们分成多个4MB的上传,并注意每个成功响应中的NextExpectedRanges字段。

相关内容

  • 没有找到相关文章