我正在尝试使用Delphi XE2中的Google Drive API,到目前为止,我几乎所有工作都在运行。我正在努力的一件事是分段上传。当我尝试上传文件时,出现503错误。通常,这应该表明服务器有问题。但是,当我使用fiddler而不是我的API将具有相同正文和标题的上传请求发送到同一网址时,该文件会成功上传。这告诉我我的代码必须有问题。这个特殊功能很乱,但现在就是这样。
function TGoogleDriveApi.MultipartUpload(aStream : TStream; aTitle : string = 'Untitled';
aDescription : string = ''; mimeType : string = 'application/octet-stream';
indexableText : IGoogleDriveIndexableText = nil;
lastViewedByMeDate : string = ''; modifiedDate : string = '';
parents : IGoogleDriveParentList = nil) : IGoogleDriveFile;
var
json, url, body, boundry, contentType : string;
ss : TStringStream;
ms : TMemoryStream;
lHttpHelper : IHttpHelper;
streamBytes : TBytes;
begin
boundry := 'a_boundry';
body := '--'+boundry+sLineBreak;
body := body + 'Content-Type: application/json; charset=UTF-8';
lHttpHelper := THttpHelper.Create;
if(Token.IsExpired) then
Token.Refresh(TokenUrl, OAuth.ClientId, OAuth.ClientSecret);
url := 'https://www.googleapis.com/upload/drive/v2/files?uploadType=multipart&access_token='+lHttpHelper.UrlEncode(Token.access_token);
json := '{';
json := json + '"title": "'+aTitle+'"';
if(aDescription <> '') then
json := json + ', "description": "'+aDescription+'"';
if(lastViewedByMeDate <> '') then
json := json + ', "lastViewedByMeDate": "'+lastViewedByMeDate+'"';
json := json + ', "mimeType": "'+mimeType+'"';
if(modifiedDate <> '') then
json := json + ', "modifiedDate": "'+modifiedDate+'"';
json := json + '}';
body := body + sLineBreak + sLineBreak + json + sLineBreak + sLineBreak + '--'+boundry;
body := body + sLineBreak + 'Content-Type: '+mimeType + sLineBreak + sLineBreak;
body := body + 'some test text from the api' + sLineBreak + sLineBreak + '--'+boundry+'--';
ss := TStringStream.Create;
ss.WriteString(body);
ss.Position := 0;
ms := TMemoryStream.Create;
ms.Write(ss,ss.Size);
SetLength(streamBytes,aStream.Size);
aStream.Read(streamBytes,aStream.Size);
ms.Write(streamBytes[0],aStream.Size);
ss.Clear;
ss.Position := 0;
ss.WriteString(sLineBreak + sLineBreak + '--'+boundry+'--');
ss.Position := 0;
ms.Write(ss,ss.Size);
contentType := 'multipart/related; boundary="'+boundry+'"';
json := lHttpHelper.PostResponse(url,contentType,ms);
FreeAndNil(ss);
FreeAndNil(ms);
Result := nil;
end;
导致问题的行是lHttpHelper.PostResponse
调用。其代码如下所示:
function THttpHelper.PostResponse(url, contentType : string; aStream : TStream) : string;
var
lHTTP: TIdHTTP;
lStream : TStringStream;
handler : TIdSSLIOHandlerSocketOpenSSL;
begin
lStream := TStringStream.Create;
lHTTP := TIdHTTP.Create(nil);
handler := TidSSLIOHandlerSocketOpenSSL.Create(nil);
handler.SSLOptions.Method := sslvSSLv3;
lHTTP.IOHandler := handler;
try
lHTTP.Request.ContentType := contentType;
lHTTP.Post(url,aStream,lStream);
lStream.Position := 0;
Result := lStream.ReadString(lStream.Size);
//except
finally
lStream.Free;
lHTTP.Free;
handler.Free;
lStream := nil;
lHTTP := nil;
handler := nil;
end;
end;
我目前正在通过我的测试调用MultipartUpload
函数,如图所示
procedure TestIGoogleDriveApi.TestMultipartUpload;
var
ReturnValue : IGoogleDriveFile;
fs : TFileStream;
begin
fs := TFileStream.Create('testupload.jpg',fmOpenRead);
ReturnValue := FIGoogleDriveApi.MultipartUpload(fs,'Test Multipart Image Upload from API.txt','test file','image/jpeg');
FreeAndNil(fs);
if(ReturnValue = nil) then
fail('ReturnValue cannot be nil');
end;
任何可能导致问题的想法?我甚至不确定此时会怀疑什么。
答案 0 :(得分:1)
你需要以某种方式关注@ RobKennedy的建议。您需要查看线路上发生的事情以进行调试。尝试使用 http 替换 https 驱动器网址,然后使用Wireshark进行跟踪。
@Hendra也是正确的,通常你的应用程序需要实现指数退避并重试500个错误,虽然我怀疑这不是你的具体问题(但是: - ))
答案 1 :(得分:1)
在我的代码中更改了两件事,并进行了一些实质性的清理后,我能够使上传工作。我所做的主要更改是将所有内容直接写入TMemoryStream
而不是TStringStream
然后写入TMemoryStream
并使用AnsiString
而不是字符串。这是我清理过的代码。
function TGoogleDriveApi.MultipartUpload(aStream: TStream; aFile: TGoogleDriveFileUp) : IGoogleDriveFile;
var
json, url, boundary, body : AnsiString;
lHttpHelper : IHttpHelper;
ms : TMemoryStream;
ss : TStringStream;
writer : IRtSerializeWriter;
reader : IRtSerializeReader;
begin
if(Token.IsExpired) then
Token.Refresh(TokenUrl, OAuth.ClientId, OAuth.ClientSecret);
lHttpHelper := THttpHelper.Create;
ss := TStringStream.Create;
writer := TRtJsonSerializeWriter.Create;
writer.SaveToStream(ss,aFile);
ss.Position := 0;
json := ss.ReadString(ss.Size);
FreeAndNil(ss);
url := 'https://www.googleapis.com/upload/drive/v2/files?uploadType=multipart&access_token='+lHttpHelper.UrlEncode(Token.access_token);
boundary := 'a_bondary';
body := '--'+boundary+sLineBreak;
body := body + 'Content-Type: application/json; charset=UTF-8' + sLineBreak + sLineBreak;
body := body + json + sLineBreak + sLineBreak +'--'+boundary;
body := body + sLineBreak + sLineBreak;
ms := TMemoryStream.Create;
ms.Write(body[1],Length(body));
ms.CopyFrom(aStream, aStream.Size);
body := sLineBreak + sLineBreak + '--' + boundary + '--';
ms.Write(body[1],Length(body));
ms.Position := 0;
json := lHttpHelper.PostResponse(url,'multipart/related; boundary="'+boundary+'"',ms);
ss := TStringStream.Create;
ss.WriteString(json);
ss.Position := 0;
reader := TRtJsonSerializeReader.Create;
Result := TGoogleDriveFileDown.Create;
reader.LoadFromStream(ss,Result as TGoogleDriveFileDown);
FreeAndNil(ms);
FreeAndNil(ss);
end;