【问题标题】:HTTP POST with HttpWebRequest带有 HttpWebRequest 的 HTTP POST
【发布时间】:2011-08-27 04:28:20
【问题描述】:

我正在尝试发布一些数据,就像我在 HTML 网站上使用 FORM 一样(ContentType = multipart/form-data)。目标是亚马逊的s3。 我正在使用 HttpWebRequest / HttpWebResponse,对我来说一切似乎都很好,但我仍然无法解决一个问题,我不断收到错误:

<?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-app 的上传生成的报告之间的唯一区别是基于 web-app 的 [TCP Segment of a reassembled PDU] 位置较少,并且有一些 [TCP Dup ACK 156#1] http > 58364 [ACK] Sq=1 Ack=7017 Win=11668 Len=0 条目(如果可能有帮助,我可以发送完整的跟踪)。

【问题讨论】:

  • 您有什么理由不想使用 Amazon 3S .NET API?

标签: .net http post httpwebrequest amazon-s3


【解决方案1】:

将其发布到您自己的服务器而不是亚马逊,然后检查 POST - 我敢打赌您的标头设置不正确,这意味着由于您使用的是多部分表单数据,因此无法解码 POST。

无论如何,您都应该使用官方 SDK。

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

【讨论】:

  • 我真的很想使用 SKD,但由于 2 个原因,这实际上是不可能的: - 据我所知,有必要在应用程序中存储密钥(这对我们来说是不可能的,因为出于安全原因)-它不支持(或者我看不到)策略设置选项,该选项启用文件的大小限制(仅启用“PUT”方法,而需要“POST”)
【解决方案2】:

解决了! 边界错误 - 需要为发布数据添加比标题中的值多 2 个破折号。 在上面的代码中需要做的是:

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

[...]

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

[...] 如此简单……却又如此烦人……

【讨论】:

    【解决方案3】:

    我花了大约三天的时间试图解决同样的问题。确保绝对确定您的 POST 正文格式使用一致的行尾。我在 CRLF 序列中忘记了一个回车符 (\r),Amazon S3 给了我这个错误和类似的错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-02
      • 2017-12-08
      • 1970-01-01
      • 1970-01-01
      • 2016-03-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多