我试图使用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."}}
CustomHeaders
中Content-Range
的消息为:
HTTP/1.1 400 Bad Request
{"error":{"code":"InvalidContentRangeHeader","message":"Invalid Content-Range header."}}
Indy中的PUT
命令是否与HTTP中的标准兼容,或者是否需要进行调整以使其工作?
Range
和Content-Range
HTTP头是两个完全不同的东西。看到内容范围和范围标头之间的区别?
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建议在使用此PUT
API时一次上传不超过4MB。您的示例文件是3.6MB,因此它只适合单个PUT
请求,但要知道,对于更大的文件,您将不得不将它们分成多个4MB的上传,并注意每个成功响应中的NextExpectedRanges
字段。