Подтвердить что ты не робот

WebRequest POST с обоими параметрами и параметрами

Я пытаюсь загрузить файл и отправить по нескольким параметрам на мой сайт с помощью .NET/С#. Прочитав несколько руководств, которые выполняют либо несколько параметров, либо файл, я попытался, безуспешно, объединить их. Вот как я это делаю:

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, говоря: "Раздел заголовка имеет более 10240 битнов (может быть, он не был надлежащим образом завершен)", и Wireshark сообщает мне, что отправленный запрос был неправильным пакетом, где MIME multipart был уродливы.

Здесь, вероятно, есть несколько вопросов, поэтому, пожалуйста, дайте мне знать все проблемы, которые вы можете обнаружить.

Обновить: чтобы отделить MIME от С#/. NET, я создал здесь поток: https://stackoverflow.com/info/1880002/error-in-mime-packet-for-http-post

Обновление 2. Таким образом, у бэкэнда действительно есть проблемы с длиной содержимого, говоря, что количество байтов, доступных для чтения, меньше заданной длины контента. НО! Если я уменьшу длину содержимого в req.ContentLength соответственно, у меня нет размера буфера, достаточно большого для отправки данных. Любые предложения?

Обновление 3. На самом деле, похоже, что заголовок имеет слишком большой размер по сравнению с тем, сколько данных он содержит.

4b9b3361

Ответ 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"

отсутствует '\n' перед 'Content-Type'. Это должно быть:

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

Ответ 2

Я предполагаю, что непосредственной проблемой является несоответствие между объявленной и фактической длиной.

Где вы просчитались, я не уверен, но если я правильно помню, длина должна включать каждый байт ответа (включая заголовки), за исключением первой строки.

Чтобы быть уверенным, что я создам простую html-страницу для создания сообщения, которое вы хотите, и просмотрите сообщение с помощью скрипача (или firebug)

Ответ 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";

Мой objective-C код для iPhone-приложения, который я использую, и который теперь работает, выглядит следующим образом:

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]);

Надеюсь, это поможет кому-то.