【问题标题】:WebRequest POST with both file and parameters带有文件和参数的 WebRequest POST
【发布时间】:2009-12-09 14:53:36
【问题描述】:

我正在尝试使用 .NET / C# 将文件和一些参数发送到我的站点。在阅读了一些使用一些参数或文件的教程后,我尝试将它们组合起来,但没有成功。以下是我尝试这样做的方法:

WebRequest req = WebRequest.Create(baseURL + "upload");
req.Credentials = new NetworkCredential(username, password);
String boundary = "B0unD-Ary";
req.ContentType = "multipart/form-data; boundary=" + boundary;
req.Method = "POST";
((HttpWebRequest)req).UserAgent = "UploadTester v0.1";

string postData = "--" + boundary + "\nContent-Disposition: form-data\n";
postData += "myId=123&someFk=456";
postData += "\n--" + boundary + "\nContent-Disposition: form-data; name=\"file\" filename=\"upload.pdf\" Content-Type: application/pdf\n\n";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);

byte[] filedata = null;
using (BinaryReader reader = new BinaryReader(File.OpenRead("myfile.pdf")))
    filedata = reader.ReadBytes((int)reader.BaseStream.Length);

req.ContentLength = byteArray.Length + filedata.Length;
req.GetRequestStream().Write(byteArray, 0, byteArray.Length);
req.GetRequestStream().Write(filedata, 0, filedata.Length);

WebResponse response = req.GetResponse();
Stream data = response.GetResponseStream();
StreamReader sReader = new StreamReader(data);
String sResponse = sReader.ReadToEnd();
response.Close();

当我执行它时,我得到一个 500 异常,说“Header section has more than 10240 bnytes (也许它没有正确终止)”并且 Wireshark 通知我发送的请求是一个格式错误的包,其中 MIME 多部分是格式错误。

这里可能有几个问题,所以请告诉我你能发现的所有问题

更新:为了将 MIME 与 C#/.NET 分开,我在这里创建了一个线程:https://stackoverflow.com/questions/1880002/error-in-mime-packet-for-http-post

更新 2:所以后端确实存在内容长度问题,表示可供读取的字节数小于规定的内容长度。但!如果我相应地减少 req.ContentLength 中的内容长度,则我没有足够大的缓冲区大小来发送数据。有什么建议吗?

更新 3:实际上,与包含的数据量相比,标题看起来太大了

【问题讨论】:

  • 如果您使用的是 .NET >= 4.0,请跳至我的答案以获得更简单的方法。

标签: c# .net http post httpwebrequest


【解决方案1】:

问题是您缺少“\n”。以下行:

string postData = "--" + boundary + "\nContent-Disposition: form-data\n";

应该是:

string postData = "--" + boundary + "\nContent-Disposition: form-data\n\n";

还有这一行:

postData += "\n--" + boundary + "\nContent-Disposition: form-data; name=\"file\" filename=\"upload.pdf\" Content-Type: application/pdf\n\n"

在“Content-Type”之前缺少一个“\n”。应该是:

postData += "\n--" + boundary + "\nContent-Disposition: form-data; name=\"file\" filename=\"upload.pdf\"\nContent-Type: application/pdf\n\n"

【讨论】:

  • 感谢您指出这些。经过 15 个小时的调试,我发现了主要问题:.NET 引擎将我所有的换行符转换为 CR+换行符,因此写入的字节数超过了我在内容长度中指定的字节数。因此,对于将来遇到类似问题的任何人:将所有换行符替换为 CR + 换行符(\n 到 \r\n)
  • 当我使用它时,我得到了 Multipart:预期的最终边界?关于如何解决这个问题的任何想法?
【解决方案2】:

我猜直接的问题是声明的长度和实际长度不匹配。

我不确定你在哪里计算错了,但如果我没记错的话,长度应该包括响应的每个字节(包括标题),除了第一行。

为了确保我会构建一个简单的 html 页面来生成您想要的帖子并使用 fiddler(或 firebug)检查帖子

【讨论】:

  • 啊,谢谢,这是一个很好的提示。很遗憾,我必须手动执行此操作。我敢肯定,成千上万的人都编写过类似这样的代码,使用标准库会更容易。
  • 嗯,但我的内容长度正确设置为 129597 字节,而不是接近 10240。:-I
  • 我不会写入请求流,而是将其写入文件流,看看有多少字节,并确保内容长度匹配。或者,写入 MemoryStream,然后您可以执行 memoryStream.ToArra() 并从中获取内容长度。
  • 每个部分都必须有自己的内容长度标头吗?如果不是,则无法判断二进制部分的结束位置
【解决方案3】:

尝试改变

string postData = "--" + boundary + "\nContent-Disposition: form-data\n";

string postData = "\n\n--" + boundary + "\nContent-Disposition: form-data\n\n";

最好也将所有\n替换为\r\n。至少前两个换行符为我解决了“标题部分超过 10240 字节(可能没有正确终止)”问题。

而且这段代码看起来不正确:

postData += "myId=123&someFk=456";

我正在使用并且现在可以运行的 iPhone 应用程序的 Objective-C 代码如下所示:

NSMutableData *reqData = [NSMutableData data];
NSURL *encUrl;
encUrl = [NSURL URLWithString:[NSString url];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:encUrl];
request.HTTPMethod = @"POST";
request.timeoutInterval = kServerConnectionTimeout;
    NSString *stringBoundary = [NSString stringWithString:@"Multipart-Boundary"]; // TODO - randomize this
    NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=\"%@\"",stringBoundary];
    [request addValue:contentType forHTTPHeaderField: @"Content-Type"];

[reqData appendData:[[NSString stringWithFormat:@"\r\n\r\n--%@\r\n",stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
for (id key in [self.parameters allKeys])
{
    if (![key isEqualToString:@"image"])
    {
        NSString *val = [self.parameters objectForKey:key];
        if (val != nil)
        {
            [reqData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n",key] dataUsingEncoding:NSUTF8StringEncoding]];
            [reqData appendData:[[NSString stringWithFormat:@"Content-Type: text/plain\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
            [reqData appendData:[[NSString stringWithFormat:@"Content-Transfer-Encoding: 8bit\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
            [reqData appendData:[[NSString stringWithFormat:@"%@",val] dataUsingEncoding:NSUTF8StringEncoding]];
            [reqData appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
        }
    }
}

// send binary part last
if ([self.parameters objectForKey:@"image"])
{
    NSString *key  = @"image";
    NSData *imageData = [self.parameters objectForKey:key];
    if (imageData != nil)
    {
        [reqData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"image\";filename=\"avatar.png\"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
        [reqData appendData:[[NSString stringWithFormat:@"Content-Type: image/png\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];

        [reqData appendData:[[NSString stringWithFormat:@"Content-Transfer-Encoding: binary\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
        [reqData appendData:imageData];
        [reqData appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
    }
}
NSString * dataLength = [NSString stringWithFormat:@"%d", [reqData length]];
[request addValue:dataLength forHTTPHeaderField:@"Content-Length"];

request.HTTPBody = reqData;
NSLog(@"postBody=%@", [[NSString alloc] initWithData:reqData encoding:NSASCIIStringEncoding]);

希望这对某人有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-06
    • 1970-01-01
    • 2023-01-23
    • 1970-01-01
    • 1970-01-01
    • 2012-08-19
    • 1970-01-01
    相关资源
    最近更新 更多