2017-02-10 17 views
0

나는 Multipart upload to OneDrive using POST을 시도하고 'HTTP/1.1 400 Bad Request'를 얻으려고합니다. IdLogFile :인디 10 Multipart가 OneDrive에 업로드 오류

 
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; 

내가 잘못 뭐하는 거지?

 
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. 
+0

당신이 작업 요청을 캡처하고 델파이 요청과 비교하는 Fiddler2를 시도? – mjn

+0

@mjn IdLogFile (Indy)을 사용합니다. 그것은 작업 요청을 캡처합니다. –

+0

작동중인 HTTP 요청도 표시하십시오. – mjn

답변

2

당신의 MIME 데이터가 서버가 그것을 거부하는 이유 즉, 형식이 잘못되었습니다 :

이 작업 요청 (목록 어린이)입니다. 당신이 볼 수 있듯이

 
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이 있어야합니다.

요청은 더이 대신 같이해야합니다 : 채우기 위해이 코드를 시도

 
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 :

말했다되고 그건
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; 

은, 인디는 일반적으로 사용되는 TIdMultipartFormDataStream 클래스가 multipart/form-data 글을 보낼 때 TIdHTTP 원 드라이브는 multipart/form-data을 지원하지만 이상한 것은 원 드라이브의 문서가 명확에만 multipart/relatedmultipart/form-data하지에 적용되는 다음, 지정하는 것입니다하지 않습니다 : 두 개 이상의 부품이 포함 된 경우

요청이 거부됩니다. 각 부분은 인 부분을 나타내며 헤더에 name 값을 지정해야합니다. 파트는 둘 다 순서가 가능하지만 먼저 메타 데이터 파트를 지정해야합니다.

그러나 코드와 마찬가지로 동일한 설명서에 제공된 예제는 multipart/related입니다. OneDrive에 업로드 할 때 multipart/form-data 또는 multipart/related을 사용할 지에 대한 Microsoft/OneDrive 포럼 및 다양한 블로그에 대한 토론이 있습니다. OneDrive 직원 한 명이이 문제가 끝날 때까지 약간의 작업이 필요하다는 것을 확인했습니다.

그냥 경우 원 드라이브 이제까지 예 TIdMultipartFormDataStream을 사용하고, 여기 multipart/form-data 지원

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; 
+0

감사합니다, @ RemyLebeau. 'Content-Type : multipart/related;'인디 10에서는 정상적으로 작동하지만 인디 9에서는 '501 요청한 기능이 구현되지 않았습니다'가 발생합니다. 동시에 파일을 보내고 OK를 저장하십시오. 나는 예외를 무시할 것이라고 생각한다. 'TIdMultipartFormDataStream'은 아직 작동하지 않습니다. –