10

Próbuję przesłać plik wideo/obrazu za pomocą metody - (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL; przy użyciu wieloczęściowych danych formularza. Ale jakoś nie jestem w stanie załadować pliku i pojawia się błąd "stream ended unexpectedly".nie można przesłać pliku przy użyciu wieloformatowych danych NSURLSession w iOS

Wymagania

  1. przesłać film/plik obrazu na serwerze
  2. App powinny wspierać przesłane tle (kontynuować proces przesyłania nawet po aplikacja przechodzi w tle)
  3. Serwer oczekuje danych będzie wysyłane przy użyciu wieloczęściowych danych formularza.

Metody/API wykorzystywane do osiągnięcia tego

  1. NSURLSession sesja tło API (Complete kod poniżej)

    2. - (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL

Wyzwania/problemy w obliczu

  1. obliczu „stream ended unexpectedly” błąd za każdym razem używam tego API dla procesu przesyłania

Punkty należy zauważyć

  1. Wysyłanie staje się skuteczne z tego samego kodu jeśli używam NSURLConnection zamiast NSURLSession.

  2. NSURLSession Proces przesyłania w tle oczekuje, że lokalizacja pliku (NSURL) jako parametr, nie akceptuje NSData. Nie pozwala nam to przekonwertować pliku na NSData przed przesłaniem, tzn. Nie możemy dodać NSData do treści pliku.

Potrzebujesz pomocy w następujących punktach

  1. Czy jest jakiś błąd w wieloczęściowy ciała formdata który jest utworzony (uwaga - ten sam kod działa z NSURLConnection)

  2. Gdzie idę źle w moim podejściu?

  3. Czy należy wprowadzić zmiany na poziomie serwera, aby obsługiwać przesyłanie NSURLSession backgroundSession? (w analizie danych lub czymś innym?)

    Oto kod, który jest używany do przesyłania plików

NSString * BoundaryConstant = @ "---------- V2ymHFg03ehbqgZCaKO6jy";

// string constant for the post parameter 'file'. My server uses this name: `file`. Your's may differ 
    NSString* FileParamConstant = @"file"; 

    // the server url to which the image (or video) is uploaded. Use your server url here 

    url=[NSURL URLWithString:[NSString stringWithFormat:@"%@%@%d",baseURL,@"posts/post/update/",createPostObject.PostID]];  


    // create request 
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; 
    [request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData]; 
    [request setHTTPShouldHandleCookies:NO]; 
    [request setTimeoutInterval:120]; 
    [request setHTTPMethod:@"POST"]; 
    [request addValue:@"multipart/form-data" forHTTPHeaderField:@"Content-Type"]; 

    [request setURL:url]; 

    // set Content-Type in HTTP header 
    NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", BoundaryConstant]; 
    [request setValue:contentType forHTTPHeaderField: @"Content-Type"]; 

    if([[NSUserDefaults standardUserDefaults] objectForKey:@"accessToken"]){ 

     [request setValue:[[NSUserDefaults standardUserDefaults] objectForKey:@"accessToken"] forHTTPHeaderField:AccessTokenKey]; 

    } 

    // post body 
    NSMutableData *body = [NSMutableData data]; 

    // add params (all params are strings) 
    for (NSString *param in self.postParams) { 

     NSLog(@"param is %@",param); 

     [body appendData:[[NSString stringWithFormat:@"--%@\r\n", BoundaryConstant] dataUsingEncoding:NSUTF8StringEncoding]]; 
     [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", param]    dataUsingEncoding:NSUTF8StringEncoding]]; 
     [body appendData:[[NSString stringWithFormat:@"%@\r\n", [self.postParams objectForKey:param]] dataUsingEncoding:NSUTF8StringEncoding]]; 
    } 

    // add video file name to body 

     [body appendData:[[NSString stringWithFormat:@"--%@\r\n", BoundaryConstant] dataUsingEncoding:NSUTF8StringEncoding]]; 
     [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"file.mp4\"\r\n", FileParamConstant] dataUsingEncoding:NSUTF8StringEncoding]]; 
     [body appendData:[[NSString stringWithString:@"Content-Type: video/mp4\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; 
     // [body appendData:self.dataToPost]; 
     [body appendData:[[NSString stringWithFormat:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; 

     [body appendData:[[NSString stringWithFormat:@"--%@--\r\n", BoundaryConstant] dataUsingEncoding:NSUTF8StringEncoding]]; 



    // setting the body of the post to the request 
    [request setHTTPBody:body]; 

    // set the content-length 
    NSString *postLength = [NSString stringWithFormat:@"%lu", (unsigned long)[body length]]; 
    [request setValue:postLength forHTTPHeaderField:@"Content-Length"]; 

    NSLog(@"Request body %@", [[NSString alloc] initWithData:[request HTTPBody] encoding:NSUTF8StringEncoding]); 

    NSURLSessionConfiguration * backgroundConfig = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"backgroundtask1"]; 

    NSURLSession *backgroundSeesion = [NSURLSession sessionWithConfiguration: backgroundConfig delegate:self delegateQueue: [NSOperationQueue mainQueue]]; 


    NSURLSessionUploadTask *uploadTask = [backgroundSeesion uploadTaskWithRequest:request fromFile:self.videoUrl]; 
    [uploadTask resume]; 
+0

Wydaje się ustawiony „Content Wpisz "dwa razy". Nie wiem, jak to działa. Nie jestem pewien co do reszty. Robię coś podobnego, ale stwórz oddzielny bufor do wysyłania (w funkcji C++) i po prostu dodaj bufor otworów. Nie muszę więc wnosić wiele więcej. –

Odpowiedz

9

Nie przesyłasz tego, co myślisz, że jesteś. Twoim zamiarem jest, aby dane o ciele były przesyłane w obecnym stanie. Zamiast tego, po wywołaniu uploadTaskWithRequest:fromFile:, ta metoda skutecznie usuwa wartości w żądaniu i zastępuje je treścią adresu URL, który przekazałeś za pomocą parametru fromFile:.

Więc jeśli nie piszemy tego bloku danych zakodowanych w formie do tego adresu URL pliku gdzieś indziej, przesyłasz ten plik samodzielnie zamiast wieloczęściowych danych formularza.

Musisz zmodyfikować swój kod, aby zapisać dane formularza w pliku zamiast przechowywać go w HTTPBody, a następnie przekazać adres URL tego pliku do parametru fromFile:.

+0

proszę podać fragment kodu, dziękuję. –

+0

1. Zmień zFile: na fromData :, i podaj wartość 'body'. – dgatwood

+0

2. Odkomentuj // [body appendData: self.dataToPost]; i zmień wartość self.dataToPost na [NSData dataWithContentsOfURL: self.videoURL]. – dgatwood

4

Aby nie marnować czasu na radzenie sobie z tym problemem.

Cały fragment na podstawie @dgatwood odpowiedź

private func http(request: URLRequest){ 
     let configuration = URLSessionConfiguration.default 
     let session = URLSession(configuration: configuration, delegate: self, delegateQueue: .main) 
     /*Tweaking*/ 
     let task = session.uploadTask(with: request, from: request.httpBody!) 
     task.resume() 
    } 

.. I nie zapomnij dodać nagłówków na żądanie obiektu jak

request.setValue("multipart/form-data; boundary=\(yourboundary)", forHTTPHeaderField: "Content-Type")