2011-05-17 91 views
1

我試圖POST一些數據,就好像我在HTML網站上使用FORM(ContentType = multipart/form-data)。目標是亞馬遜的S3。 我使用的HttpWebRequest/HttpWebResponse和一切似乎有種沒什麼問題,但我還是不能打一個問題,我不斷收到錯誤:HTTP POST with HttpWebRequest

<?xml version="1.0" encoding="UTF-8"?> 
<Error> 
    <Code>InvalidArgument</Code> 
    <Message>POST requires exactly one file upload per request.</Message> 
    <ArgumentValue>0</ArgumentValue> 
    <ArgumentName>file</ArgumentName> 
</Error> 

這似乎是自描述的,但我真的發送「文件」字段。我已經設法通過測試網站發送沒有問題的文件,整個後期數據似乎是完全一樣的。 當我通過wireshark將所有標題和發佈數據「偵察到」請求時 - 就像預期的那樣。

有沒有人有任何想法,爲什麼亞馬遜不能看到「文件」字段?使用

代碼(它切了一下,使它更具可讀性):

private void addStringToStream(string buff, Stream s) 
{ 
    var bytes = Encoding.UTF8.GetBytes(buff); 
    s.Write(bytes, 0, bytes.Length); 

    counter += bytes.Length; 
} 

private void doPost() 
{ 
    HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url); 

    request.Method = "POST"; 
    request.ProtocolVersion = new Version(1, 1); 

    request.KeepAlive = true; 
    request.AllowAutoRedirect = true; 

    request.Headers.Add("Accept-Language", "en-us,en;q=0.5"); 
    request.Headers.Add("Accept-Encoding", "gzip,deflate"); 
    request.Headers.Add("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7"); 

    request.Accept = "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"; 
    request.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.10) Gecko/20071115 Firefox/2.0.0.10"; 

    string boundary = "---------------------------317205771417341028"; 
    request.ContentType = "multipart/form-data; boundary=" + boundary; 

    request.SendChunked = false; 
    request.Credentials = CredentialCache.DefaultCredentials; 
    request.CookieContainer = new CookieContainer(); 

    request.ContentLength = calculateLength(); 

    using (Stream s = request.GetRequestStream()) 
    { 
     boundary += "\n"; 

     string inLineContentH = "Content-Disposition: form-data; name=\"{0}\""; 
     string contentH = "Content-Disposition: form-data; name=\"{0}\"" + "\n" + "\n"; 

     string keyH = "key"; 

     string aclH = "acl"; 
     string aclV = "public-read"; 

     string accessKeyH = "AWSAccessKeyId"; 
     string accessKeyV = publicKey; 

     string policyH = "policy"; 
     string policyV = this.generatePolicy(); 

     string signatureH = "signature"; 
     string signatureV = generateSignature(policyV); 

     string fileH = "file"; 
     string fileContentNameH = "filename=\"{0}\""; 
     string contentType2H = "Content-Type: application/octet-stream"; 

     buff = boundary; 
     addStringToStream(buff, s); 

     buff = string.Format(contentH, keyH); 
     addStringToStream(buff, s); 

     buff = keyV + "\n"; 
     addStringToStream(buff, s); 

     /* here are all of the others necessary fields added to stream just as the one above 
     no other operations are used, just adding bytes to stream 
     and finally we get to the file: */ 

     buff = boundary; 
     addStringToStream(buff, s); 

     buff = string.Format(inLineContentH, fileH) + "; " + string.Format(fileContentNameH, Path.GetFileName(this.FilePath)) + "\n"; 
     addStringToStream(buff, s); 

     buff = contentType2H + "\n" + "\n"; 
     addStringToStream(buff, s); 

     var inStream = File.OpenRead(FilePath); 
     int val; 
     while ((val = inStream.ReadByte()) != -1) 
     { 
      s.WriteByte((byte)val); 
      counter++; 
     } 

     buff = "\n"; 
     addStringToStream(buff, s); 

     buff = boundary; 
     addStringToStream(buff, s); 

     buff = string.Format(contentH, "submit"); 
     addStringToStream(buff, s); 

     buff = "Upload to Amazon S3" + "\n"; 
     addStringToStream(buff, s); 

     buff = boundary.Replace("\r", "").Replace("\n", "") + "--"; 
     addStringToStream(buff, s); 
    } 

    request.GetResponse(); 
} 

後的數據去流:

---------------------------317205771417341028 
Content-Disposition: form-data; name="key" 

webtest/image.png 
---------------------------317205771417341028 
Content-Disposition: form-data; name="acl" 

public-read 
---------------------------317205771417341028 
Content-Disposition: form-data; name="AWSAccessKeyId" 

AKIAJOQLTUC5H2NJ65NA 
---------------------------317205771417341028 
Content-Disposition: form-data; name="policy" 

Oi8vd3d3Lmdvb2dsZS[...]c3QiXSwNCiAgXQ0KfQ0K 
---------------------------317205771417341028 
Content-Disposition: form-data; name="Signature" 

06GBK5DJ71aB[...]M8Ct8JOE= 
---------------------------317205771417341028 
Content-Disposition: form-data; name="file"; filename="eclipse.png" 
Content-Type: application/octet-stream 

‰PNG 

IHDRn 
[...the rest of the image...] 
IEND®B‚ 
---------------------------317205771417341028 
Content-Disposition: form-data; name="submit" 

Upload to Amazon S3 
---------------------------317205771417341028-- 

和... Wireshark的名單:

OUT TCP 58383 > http [SYN] Seq=0 Win=8192 Len=0 MSS=1460 WS=2 SACK_PERM=1 
IN TCP http > 58383 [SYN, ACK] Seq=0 Ack=1 Win=8190 Len=0 MSS=1460 WS=6 SACK_PERM=1 
OUT TCP 58383 > http [ACK] Seq=1 Ack=1 Win=65700 Len=0 
OUT TCP [TCP segment of a reassembled PDU] 
IN HTTP HTTP/1.1 100 Continue 
OUT TCP [TCP segment of a reassembled PDU] 
OUT TCP [TCP segment of a reassembled PDU] 
OUT TCP [TCP segment of a reassembled PDU] 
OUT TCP [TCP segment of a reassembled PDU] 
IN TCP http > 58383 [ACK] Seq=26 Ack=2031 Win=1331456 Len=0 
OUT TCP [TCP segment of a reassembled PDU] 
OUT TCP [TCP segment of a reassembled PDU] 
IN TCP http > 58383 [ACK] Seq=26 Ack=3969 Win=1337344 Len=0 
OUT TCP [TCP segment of a reassembled PDU] 
OUT TCP [TCP segment of a reassembled PDU] 
IN TCP http > 58383 [ACK] Seq=26 Ack=6889 Win=1343232 Len=0 
OUT TCP [TCP segment of a reassembled PDU] 
OUT TCP [TCP segment of a reassembled PDU] 
IN TCP http > 58383 [ACK] Seq=26 Ack=8441 Win=1346048 Len=0 
OUT HTTP POST/HTTP/1.1 
//the one above contains the last bytes added to the stream 
IN TCP http > 58383 [ACK] Seq=26 Ack=10225 Win=1348864 Len=0 
IN TCP http > 58383 [ACK] Seq=26 Ack=10857 Win=1351936 Len=0 
IN TCP http > 58383 [ACK] Seq=26 Ack=12162 Win=1354752 Len=0 
IN TCP http > 58383 [ACK] Seq=26 Ack=13622 Win=1357824 Len=0 
IN TCP http > 58383 [ACK] Seq=26 Ack=13913 Win=1360640 Len=0 
IN TCP [TCP segment of a reassembled PDU] 
IN HTTP/XML HTTP/1.1 400 Bad Request 
//the one above includes the error info quoted in the beginning 
IN TCP http > 58383 [FIN, ACK] Seq=649 Ack=13913 Win=1360640 Len=0 
OUT TCP 58383 > http [ACK] Seq=13913 Ack=650 Win=65052 Len=0 
OUT TCP 58383 > http [FIN, ACK] Seq=13913 Ack=650 Win=65052 Len=0 
IN TCP http > 58383 [ACK] Seq=650 Ack=13914 Win=1360640 Len=0 

上述報告和基於網絡應用程序的上載生成的報告之間的唯一區別是基於Web應用程序[重新組裝的PDU的TCP段]位置,並且具有一些[TCP Dup ACK 156#1] http> 58364 [ACK] Sq = 1 Ack = 7017 Win = 11668 Len = 0條目(如果可能會有所幫助我可以發送完整跟蹤)。

+0

你有什麼理由不想使用Amazon 3S .NET API? – 2011-05-17 12:03:53

回答

1

解決了! 邊界是錯誤的 - 需要爲發佈數據添加2個破折號而不是標題中的值。 需要在上面的代碼做什麼:

string boundary = "---------------------------317205771417341028"; 
request.ContentType = "multipart/form-data; boundary=" + boundary; 

[...]

using (Stream s = request.GetRequestStream()) 
{ 
    boundary = "--" + boundary "\n"; 

[...] 那麼容易......卻又是那麼討厭...

0

將您的郵件發送到您自己的服務器而不是Amazon,然後檢查POST - 我敢打賭,您的郵件頭設置不正確,這意味着因爲您使用的是多部分表單數據,所以POST無法解碼。

反正你應該使用官方的SDK。

http://aws.amazon.com/sdkfornet/

+0

我真的很喜歡使用SKD,但由於以下兩個原因,並不是真的可能: - 據我所知有必要在應用程序中存儲密鑰(由於安全原因,這對我們來說是不可能的) - 它不支持(或者我盲目地看到)策略設置選項,該選項可以啓用文件的大小限制(僅在「POST」需要時啓用「PUT」方法) – 2011-06-07 14:51:13

0

我花了大約三天的時間試圖解決同樣的問題。製作絕對確定您使用一致的行結尾符合您的POST正文格式。我忘記了CRLF序列中的單個回車(\r),並且Amazon S3給了我這個錯誤和類似的錯誤。