2

DelphiXE2でGoogleDriveAPIを使用しようとしていますが、これまでのところ、ほぼすべてが機能しています。私が苦労していることの1つは、マルチパートアップロードです。ファイルをアップロードしようとすると、503エラーが発生します。通常、これはサーバーに問題があることを示しているはずです。ただし、APIではなくfiddlerを使用して、同じ本文とヘッダーを含むアップロードリクエストを同じURLに送信すると、ファイルは正常にアップロードされます。これは、私のコードに問題があるはずだということを教えてくれます。この特定の機能はめちゃくちゃですが、ここにあります。

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;

問題を引き起こしている可能性のあるアイデアはありますか?この時点で何を疑うべきかさえわかりません。

4

2 に答える 2

1

どういうわけか@RobKennedyのアドバイスに従う必要があります。これをデバッグするには、ネットワーク上で何が起こっているかを確認する必要があります。httpsドライブのURLをhttpに置き換えてから、Wiresharkでトレースしてみてください。

@Hendraも正しいです。通常、アプリは指数バックオフを実装し、500エラーを再試行する必要がありますが、それは特定の問題ではないと思います(まだ:-))

于 2012-09-28T07:48:49.613 に答える
1

コード内の2つのことを変更し、かなりのクリーンアップを行った後、アップロードを機能させることができました。私が行った主な変更は、すべてを、 thenTMemoryStreamではなくaに直接書き込み、文字列ではなくsを使用することでした。これが私のクリーンアップされたコードです。TStringStreamTMemoryStreamAnsiString

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;
于 2012-09-28T23:11:26.880 に答える