Indy 10分段上传到OneDrive错误 [英] Indy 10 Multipart upload to OneDrive Error

查看:126
本文介绍了Indy 10分段上传到OneDrive错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用POST分段上传到OneDrive,并获取'HTTP /1.1 400错误的请求". IdLogFile:

I am trying to do Multipart upload to OneDrive using POST and get 'HTTP/1.1 400 Bad Request'. IdLogFile:


Stat Connected.
Sent 10.02.2017 12:50:08: POST /v1.0/drive/root::/children HTTP/1.0`<EOL>`Content-Type: multipart/related; boundary="Boundary"`<EOL>`Content-Length: 254`<EOL>`Authorization: Bearer EwA...%3d`<EOL>`Host: api.onedrive.com`<EOL>`Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8`<EOL>`Accept-Encoding: identity`<EOL>`User-Agent: Mozilla/3.0 (compatible; Indy Library)`<EOL><EOL>`
Sent 10.02.2017 12:50:08: --Boundary`<EOL>`Content-ID: <metadata>`<EOL>`Content-Type: application/json`<EOL>`{"name":"Dest.txt", "file":{}, "@content.sourceUrl":"cid:content"}`<EOL>`--Boundary`<EOL>`Content-ID: <content><EOL>Content-Type: application/octet-stream<SourceContent>--Boundary--
Recv 10.02.2017 12:50:08: H
Recv 10.02.2017 12:50:08: TTP/1.1 400 Bad Request`<EOL>`Via: 1.1 DM5SCH102210409 (wls-colorado)`<EOL>`Content-Length: 60`<EOL>`Content-Type: application/json`<EOL>`Server: Microsoft-IIS/8.5`<EOL>`P3P: CP="BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo"`<EOL>`X-WLSPROXY: DM5SCH102210409`<EOL>`X-MSNSERVER: DM5SCH102231823`<EOL>`Strict-Transport-Security: max-age=31536000; includeSubDomains`<EOL>`X-QosStats: {"ApiId":0,"ResultType":2,"SourcePropertyId":0,"TargetPropertyId":42}`<EOL>`X-ThrowSite: 1479.b891`<EOL>`X-AsmVersion: UNKNOWN; 16.0.0.0`<EOL>`X-MSEdge-Ref: Ref A: A9918FA26FAF469EB3797E9DAEA3172E Ref B: FRAEDGE0409 Ref C: Fri Feb 10 01:50:09 2017 PST`<EOL>`Date: Fri, 10 Feb 2017 09:50:09 GMT`<EOL>`Connection: close`<EOL><EOL>`{"error":{"code":"invalidRequest","message":"Bad Argument"}}
Stat Disconnected.

代码:

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;

我在做什么错了?

这是一个工作请求(列出孩子):

This is a working request (List children):


Stat Connected.
Sent 10.02.2017 20:52:42: GET /v1.0/drive/root::/children?select=name,folder,file HTTP/1.1`<EOL>`Authorization: Bearer EwA...%3d`<EOL>`Host: api.onedrive.com`<EOL>`Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8`<EOL>`Accept-Encoding: identity`<EOL>`User-Agent: Mozilla/3.0 (compatible; Indy Library)`<EOL>``<EOL>`
Recv 10.02.2017 20:52:43: H
Recv 10.02.2017 20:52:43: TTP/1.1 200 OK`<EOL>`Via: 1.1 BN2BAP4ED8CB55D (wls-colorado)`<EOL>`Content-Length: 213`<EOL>`Content-Type: application/json; odata.metadata=minimal`<EOL>`Server: Microsoft-IIS/8.5`<EOL>`P3P: CP="BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo"`<EOL>`X-WLSPROXY: BN2BAP4ED8CB55D``X-MSNSERVER: DM5SCH102231619`<EOL>`Strict-Transport-Security: max-age=31536000; includeSubDomains`<EOL>`OData-Version: 4.0`<EOL>`X-AsmVersion: UNKNOWN; 16.0.0.0`<EOL>`X-MSEdge-Ref: Ref A: ECB06A4BE05B478AB36611C892C36CC7 Ref B: AM1EDGE0419 Ref C: Fri Feb 10 09:52:43 2017 PST``Date: Fri, 10 Feb 2017 17:52:43 GMT`<EOL>``<EOL>`{"@odata.context":"https://api.onedrive.com/v1.0/$metadata#drives('me')/items('root')/children(name,folder,file)","value":[{"name":"AB","folder":{"childCount":7}},{"name":"ArecaBackup","folder":{"childCount":6}}]}
Stat Disconnected.

推荐答案

您的MIME数据格式错误,这就是服务器拒绝它的原因.

Your MIME data is malformed, that is why the server is rejecting it.

这是您要发送的请求:


POST /v1.0/drive/root::/children HTTP/1.0
Content-Type: multipart/related; boundary="Boundary"
Content-Length: 254
Authorization: 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 (compatible; Indy Library)

--Boundary
Content-ID: <metadata>
Content-Type: application/json
{"name":"Dest.txt", "file":{}, "@content.sourceUrl":"cid:content"}
--Boundary
Content-ID: <content>
Content-Type: application/octet-stream<SourceContent>--Boundary--

如您所见,MIME数据都被弄乱了.具体来说,每个MIME字段都缺少一些必需的CRLF.就像HTTP标头和正文一样,MIME标头和正文由<CRLF><CRLF>序列分隔,并且TFileStream数据与其后的MIME边界之间必须有一个CRLF.

As you can see, the MIME data is all messed up. Specifically, each MIME field is missing some required CRLFs. Just like with the HTTP headers and body, MIME headers and body are separated by a <CRLF><CRLF> sequence, and there needs to be a CRLF between the TFileStream data and the MIME boundary that follows it.

请求看起来应该更像这样:

The request needs to look more like this instead:


POST /v1.0/drive/root::/children HTTP/1.0
Content-Type: multipart/related; boundary="Boundary"
Content-Length: 260
Authorization: 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 (compatible; Indy Library)

--Boundary
Content-ID: <metadata>
Content-Type: application/json

{"name":"Dest.txt", "file":{}, "@content.sourceUrl":"cid:content"}
--Boundary
Content-ID: <content>
Content-Type: application/octet-stream

<SourceContent>
--Boundary--

尝试使用以下代码填充TMemoryStream:

Try this code to populate the 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:

That being said, Indy has a TIdMultipartFormDataStream class that is typically used with TIdHTTP when sending multipart/form-data posts. OneDrive does not support multipart/form-data, but what is odd is that OneDrive's documentation clearly specifies the following, which only applies to multipart/form-data and not to multipart/related:

如果包含两个以上的部分,则该请求将被拒绝. 每个部分都必须在Content-Disposition标头中指定一个name值,以指示它是哪个部分.零件可以采用任何顺序,但应首先指定元数据零件.

The request will be rejected if more than two parts are included. Each part must specify a name value in the Content-Disposition header that indicates which part it is. Parts can be in either order, but should specify the metadata part first.

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

However, the example given in the same documentation is using multipart/related, just like your code is. There are discussions in Microsoft/OneDrive forums and various blogs regarding whether to use multipart/form-data or multipart/related when uploading to OneDrive. One OneDrive employee did confirm this issue needs some work on their end.

仅在OneDrive支持multipart/form-data的情况下,这是使用TIdMultipartFormDataStream的示例:

Just in case OneDrive ever supports multipart/form-data, here is a example using 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;

这篇关于Indy 10分段上传到OneDrive错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆