2009-12-09 1 views
12

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

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 bnytes (может быть, это не правильно прекращено)» и Wireshark сообщает мне, что запрос отправлен был неправильным пакетом, в котором MIME-мультипорт был искажен.

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

Update:. Отделить MIME от C#/.NET, я породил поток здесь: https://stackoverflow.com/questions/1880002/error-in-mime-packet-for-http-post

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

Update 3: На самом деле, это выглядит как заголовок имеет слишком большой размер по сравнению с тем, сколько данных содержит

+0

Если вы используете .NET> = 4.0, пропустите свой ответ для более легкого способа сделать это. – Joshcodes

ответ

11

Проблема в том, что вы не нашли «\ п». Следующая строка:

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'. Оно должно быть:

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

Спасибо, что указали их. После долгих 15 часов отладки я нашел основную проблему: механизм .NET переводит все мои строки в CR + Newline, тем самым записывая больше байтов, чем я указал в контенте. Итак, для тех, у кого есть аналогичная проблема в будущем: замените все новые строки на CR + newline (\ n на \ r \ n) – niklassaers

+0

Я использую это, получаю Multipart: ожидается финальная граница? Любая идея о том, как решить эту проблему? –

1

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

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

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

+0

А, спасибо, это хороший намек. Жаль, что я должен это сделать вручную. Я уверен, что тысячи людей написали код, похожий на это, было бы проще со стандартной библиотекой. – niklassaers

+0

Хм, но длина моего контента правильно установлена ​​в 129597 байт, а не где-то около 10240.: -I – niklassaers

+0

Вместо того, чтобы писать в поток запроса, я бы записал его в поток и посмотрел, сколько там байтов, и убедитесь, что что длина содержимого соответствует. Или поочередно записывайте в MemoryStream, затем вы можете сделать memoryStream.ToArra() и получить длину контента от этого. – feroze

0

Попробуйте изменить

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

в

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

И лучше также заменить все \ п \ к г \ п. По крайней мере, первые две новые строки работали для меня, чтобы решить «Раздел заголовка имеет более чем 10240 байт (возможно, он не правильно завершен)».

И этот код не выглядит правильно:

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

Моей цель-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]); 

Надеется, что это помогает кто-то.