2009-12-09 10 views
12

Tôi đang cố tải lên tệp và gửi cùng một vài tham số đến trang web của mình bằng .NET/C#. Sau khi đọc một vài hướng dẫn thực hiện một vài tham số hoặc một tệp, tôi đã thử, không thành công, để kết hợp chúng. Dưới đây là cách tôi cố gắng làm việc đó:WebRequest POST với cả tệp và thông số

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

Khi tôi thực hiện nó, tôi nhận được một ngoại lệ 500, nói rằng "phần header đã có hơn 10.240 bnytes (có thể nó không bị chấm dứt đúng)" và Wireshark thông báo với tôi rằng yêu cầu đã gửi là gói không đúng định dạng, trong đó đa phần MIME không đúng định dạng.

Có lẽ một số vấn đề ở đây, vì vậy xin vui lòng cho tôi biết tất cả các vấn đề bạn có thể nhận ra

Cập nhật:. Để tách MIME từ C NET # /, tôi đã sinh ra một sợi đây: https://stackoverflow.com/questions/1880002/error-in-mime-packet-for-http-post

Cập nhật 2: Vì vậy, chương trình phụ trợ thực sự có vấn đề với độ dài nội dung, nói rằng số lượng byte có sẵn để đọc nhỏ hơn chiều dài nội dung đã nêu. NHƯNG! Nếu tôi giảm độ dài nội dung trong req.ContentLength cho phù hợp, tôi không có kích thước bộ đệm đủ lớn để gửi dữ liệu. Bất kỳ đề xuất?

Cập nhật 3: Trên thực tế, có vẻ như tiêu đề có kích thước quá lớn so với bao nhiêu dữ liệu mà nó chứa

+0

Nếu bạn đang sử dụng .NET> = 4.0, hãy bỏ qua câu trả lời của tôi để có cách dễ dàng hơn để thực hiện việc này. – Joshcodes

Trả lời

11

Vấn đề là bạn đang bỏ lỡ một '\ n'. Các dòng sau:

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

nên là:

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

Và dòng này:

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

thiếu '\ n' trước khi 'Content-Type'. Nó nên là:

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

Cảm ơn bạn đã chỉ ra những điều này. Sau 15 giờ gỡ rối, tôi đã tìm thấy vấn đề chính: Công cụ .NET dịch tất cả các dòng mới của tôi thành CR + Newline, do đó viết nhiều byte hơn số byte tôi đã chỉ định trong chiều dài nội dung. Vì vậy, đối với bất kỳ ai có vấn đề tương tự trong tương lai: hãy thay thế tất cả dòng mới bằng CR + newline (\ n thành \ r \ n) – niklassaers

+0

mà tôi sử dụng tính năng này để nhận Multipart: ranh giới cuối cùng được mong đợi? Bất kỳ ý tưởng về cách giải quyết vấn đề đó? –

1

Tôi đoán các vấn đề trước mắt là không phù hợp giữa tuyên bố và độ dài thực tế.

Trường hợp bạn đã tính sai tôi không chắc chắn nhưng nếu tôi nhớ chính xác độ dài nên bao gồm mọi byte của phản hồi (bao gồm tiêu đề) ngoại trừ dòng đầu tiên.

Để chắc chắn tôi sẽ xây dựng một trang html đơn giản để tạo ra các bài mà bạn muốn và kiểm tra bài với cáy (hoặc firebug)

+0

Ah, cảm ơn, đó là một gợi ý tốt. Thật đáng tiếc là tôi phải làm điều này bằng tay. Tôi chắc rằng hàng ngàn người đã viết mã khá nhiều như thế này, sẽ dễ dàng hơn với một thư viện chuẩn. – niklassaers

+0

Hmm, nhưng độ dài nội dung của tôi được đặt thành 129597 byte, không phải ở bất kỳ đâu gần 10240.: -I – niklassaers

+0

Thay vì ghi vào luồng yêu cầu, tôi sẽ ghi nó vào luồng phim và xem có bao nhiêu byte và đảm bảo độ dài nội dung phù hợp. Hoặc luân phiên, ghi vào MemoryStream, sau đó bạn có thể thực hiện một memoryStream.ToArra() và lấy chiều dài nội dung từ đó. – feroze

0

Cố gắng thay đổi

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

để

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

Và tốt hơn cũng thay thế tất cả \ n \ r \ n. Ít nhất đầu tiên hai dòng mới làm việc cho tôi giải quyết "Tiêu đề phần có hơn 10240 byte (có thể nó không phải là chấm dứt đúng)" vấn đề.

Và mã này không giống chính xác:

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

Mã của tôi Mục tiêu-C cho ứng dụng iPhone mà tôi đang sử dụng và mà làm việc bây giờ trông như thế này:

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

Hope this helps có ai.