【问题标题】:Indy 10 Multipart upload to OneDrive ErrorIndy 10 分段上传到 OneDrive 错误
【发布时间】:2017-06-28 16:00:23
【问题描述】:

我正在尝试执行 Multipart upload to OneDrive using POST 并获得“HTTP/1.1 400 Bad Request”。标识日志文件:

统计连接。 发送 10.02.2017 12:50:08: POST /v1.0/drive/root::/children HTTP/1.0``Content-Type: multipart/related; boundary="Boundary"``Content-Length: 254``授权:Bearer EwA...%3d``Host: api.onedrive.com``Accept: text/ html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8``Accept-Encoding: identity``User-Agent: Mozilla/3.0(兼容;Indy Library )`` 发送时间 10.02.2017 12:50:08:--Boundary``Content-ID: ``Content-Type: application/json``{"name":"Dest. txt", "file":{}, "@content.sourceUrl":"cid:content"}``--Boundary``Content-ID: Content-Type: application/octet-stream--边界-- 接收 10.02.2017 12:50:08: H Recv 10.02.2017 12:50:08:TTP/1.1 400 错误请求``Via: 1.1 DM5SCH102210409 (wls-colorado)``Content-Length: 60``Content-Type: application /json``服务器:Microsoft-IIS/8.5``P3P: CP="BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo"``X-WLSPROXY: DM5SCH102210409`` X-MSNSERVER: DM5SCH102231823``Strict-Transport-Security: max-age=31536000; includeSubDomains``X-QosStats: {"ApiId":0,"ResultType":2,"SourcePropertyId":0,"TargetPropertyId":42}``X-ThrowSite: 1479.b891``X-AsmVersion:未知; 16.0.0.0``X-MSEdge-Ref:Ref A:A9918FA26FAF469EB3797E9DAEA3172E Ref B:FRAEDGE0409 Ref C:2017 年 2 月 10 日星期五 01:50:09 PST``日期:2017 年 2 月 10 日星期五 09:50 :09 GMT``Connection: close``{"error":{"code":"invalidRequest","message":"Bad Argument"}} 统计断开。

代码:

procedure TSaveFilter.UploadTest;
const
  URL = 'https://api.onedrive.com/v1.0/drive/root::/children';
  Boundary = 'Boundary';
var
  IdHTTP: TIdHTTP;
  MemoryStream: TMemoryStream;
  FileStream: TFileStream;

  procedure WriteLnString(str: AnsiString; CRLF: Boolean = True);
  begin
    if CRLF then str := str + #13#10;
    MemoryStream.Write(str[1], Length(str));
  end;
begin
  IdHTTP := TIdHTTP.Create(nil);
  try
    IdHTTP.HandleRedirects := True;
    IdHTTP.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP);
    IdHTTP.Request.BasicAuthentication := False;
    IdHTTP.Request.CustomHeaders.Values['Authorization'] := 'Bearer ' + FAccessToken;
    IdHTTP.Request.ContentType := Format('multipart/related; boundary="%s"', [Boundary]);

    MemoryStream := TMemoryStream.Create;
    try
      WriteLnString('--' + Boundary);
      WriteLnString('Content-ID: <metadata>');
      WriteLnString('Content-Type: application/json');
      WriteLnString('{"name":"Dest.txt", "file":{}, "@content.sourceUrl":"cid:content"}');
      WriteLnString('--' + Boundary);
      WriteLnString('Content-ID: <content>');
      WriteLnString('Content-Type: application/octet-stream', False);
      FileStream := TFileStream.Create('Source.txt', fmOpenRead);
      try
        MemoryStream.CopyFrom(FileStream, FileStream.Size);
      finally
        FileStream.Free;
      end;
      WriteLnString('--' + Boundary + '--', False);
      IdHTTP.Post(URL, MemoryStream);
    finally
      MemoryStream.Free;
    end;
  finally
    IdHTTP.Free;
  end;
end;

我做错了什么?

这是一个有效的请求(列出孩子):

统计连接。 发送 10.02.2017 20:52:42: GET /v1.0/drive/root::/children?select=name,folder,file HTTP/1.1``授权: Bearer EwA...%3d``Host: api.onedrive.com``Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8``Accept-Encoding : 身份``用户代理:Mozilla/3.0(兼容;Indy 库)```` 接收 10.02.2017 20:52:43: H Recv 10.02.2017 20:52:43: TTP/1.1 200 OK``Via: 1.1 BN2BAP4ED8CB55D (wls-colorado)``Content-Length: 213``Content-Type: application/ json; odata.metadata=minimal``Server: Microsoft-IIS/8.5``P3P: CP="BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo"``X-WLSPROXY: BN2BAP4ED8CB55D` X-MSNSERVER: DM5SCH102231619``Strict-Transport-Security: max-age=31536000; includeSubDomains``OData-Version: 4.0``X-AsmVersion: UNKNOWN; 16.0.0.0``X-MSEdge-Ref:参考 A:ECB06A4BE05B478AB36611C892C36CC7 参考 B:AM1EDGE0419 参考 C:2017 年 2 月 10 日星期五 09:52:43 PST``日期:2017 年 2 月 10 日星期五 17:52:43 GMT ````{"@odata.context":"https://api.onedrive.com/v1.0/$metadata#drives('me')/items('root')/孩子(名称,文件夹,文件)“,值”:[{“名称”:“AB”,“文件夹”:{“childCount”:7}},{“名称”:“ArecaBackup”,“文件夹”: {"childCount":6}}]} 统计断开。

【问题讨论】:

  • 你试过 Fiddler2 捕获一个工作请求,并将它与 Delphi 请求进行比较吗?
  • @mjn 我使用 IdLogFile (Indy)。它捕获工作请求。
  • 请也显示有效的 HTTP 请求
  • @mjn 工作请求太大,无法发表评论 - 在问题中添加。
  • 抱歉不清楚。我想建议的是:使用不同的客户端,例如 C# 或 Java 版本。用它执行相同的请求,并捕获它的 HTTP 流量。然后,您可以将该工作请求与 Delphi 客户端的相同 HTTP 流量进行比较。

标签: delphi indy indy10 onedrive


【解决方案1】:

您的 MIME 数据格式不正确,这就是服务器拒绝它的原因。

这是您发送的请求:

POST /v1.0/drive/root::/children HTTP/1.0 内容类型:多部分/相关;边界="边界" 内容长度:254 授权:不记名 EwA...%3d 主办方:api.onedrive.com 接受:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 接受编码:身份 用户代理:Mozilla/3.0(兼容;Indy 库) - 边界 内容 ID: 内容类型:应用程序/json {"name":"Dest.txt", "file":{}, "@content.sourceUrl":"cid:content"} - 边界 内容 ID: Content-Type: application/octet-stream--Boundary--

如您所见,MIME 数据全乱了。具体来说,每个 MIME 字段都缺少一些必需的CRLFs。就像 HTTP 标头和正文一样,MIME 标头和正文由 &lt;CRLF&gt;&lt;CRLF&gt; 序列分隔,TFileStream 数据和其后的 MIME 边界之间需要有 CRLF

请求需要看起来更像这样:

POST /v1.0/drive/root::/children HTTP/1.0 内容类型:多部分/相关;边界="边界" 内容长度:260 授权:不记名 EwA...%3d 主办方:api.onedrive.com 接受:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 接受编码:身份 用户代理:Mozilla/3.0(兼容;Indy 库) - 边界 内容 ID: 内容类型:应用程序/json {"name":"Dest.txt", "file":{}, "@content.sourceUrl":"cid:content"} - 边界 内容 ID: 内容类型:应用程序/八位字节流 - 边界 -

尝试使用此代码填充TMemoryStream

MemoryStream := TMemoryStream.Create;
try
  WriteLnString('--' + Boundary);
  WriteLnString('Content-ID: <metadata>');
  WriteLnString('Content-Type: application/json');
  WriteLnString(''); // <-- ADD THIS!!!
  WriteLnString('{"name":"Dest.txt", "file":{}, "@content.sourceUrl":"cid:content"}');
  WriteLnString('--' + Boundary);
  WriteLnString('Content-ID: <content>');
  WriteLnString('Content-Type: application/octet-stream'); // <-- REMOVE THE FALSE!!!
  WriteLnString(''); // <-- ADD THIS!!!

  FileStream := TFileStream.Create('Source.txt', fmOpenRead);
  try
    MemoryStream.CopyFrom(FileStream, 0);
  finally
    FileStream.Free;
  end;

  WriteLnString(''); // <!-- ADD THIS!!!
  WriteLnString('--' + Boundary + '--', False);
  ...
finally
  MemoryStream.Free;
end;

话虽如此,Indy 有一个TIdMultipartFormDataStream 类,通常在发送multipart/form-data 帖子时与TIdHTTP 一起使用。 OneDrive 不支持multipart/form-data,但奇怪的是,OneDrive 的文档明确指定了以下内容,仅适用于multipart/form-data,不适用于multipart/related

如果包含两个以上的部分,请求将被拒绝。 每个部分都必须在Content-Disposition 标头中指定一个name 值来指示它是哪个部分。部分可以按任意顺序排列,但应首先指定元数据部分。

但是,同一文档中给出的示例使用multipart/related,就像您的代码一样。 Microsoft/OneDrive 论坛和各种博客中都有关于上传到 OneDrive 时是否使用multipart/form-datamultipart/related 的讨论。 OneDrive 员工确实确认此问题需要解决。

以防万一 OneDrive 支持 multipart/form-data,这里是一个使用 TIdMultipartFormDataStream 的示例:

procedure TSaveFilter.UploadTest;
const
  URL = 'https://api.onedrive.com/v1.0/drive/root::/children';
var
  IdHTTP: TIdHTTP;
  PostData: TIdMultipartFormDataStream;
begin
  IdHTTP := TIdHTTP.Create(nil);
  try
    IdHTTP.HandleRedirects := True;
    IdHTTP.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP);
    IdHTTP.Request.BasicAuthentication := False;
    IdHTTP.Request.CustomHeaders.Values['Authorization'] := 'Bearer ' + FAccessToken;

    PostData := TIdMultipartFormDataStream.Create;
    try
      PostData.AddFormField('metadata', '{"name":"Dest.txt", "file":{}}', 'utf-8', 'application/json');
      PostData.AddFile('content', 'Source.txt', 'application/octet-stream').FileName := '';
      IdHTTP.Post(URL, PostData);
    finally
      PostData.Free;
    end;
  finally
    IdHTTP.Free;
  end;
end;

【讨论】:

  • 谢谢@RemyLebeau。 Content-Type: multipart/related; 在 Indy 10 上工作正常,但在 Indy 9 上会导致“501 The requested feature is not implemented”。发送文件,同时保存好。我想我会忽略异常。 TIdMultipartFormDataStream 暂时还不行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-22
  • 2015-12-28
  • 2018-06-02
  • 1970-01-01
相关资源
最近更新 更多