10

Sto tentando di caricare un file video/immagine utilizzando il metodo - (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL; utilizzando dati di modulo multiparte. Ma in qualche modo non sono in grado di caricare il file e sto ricevendo l'errore "stream ended unexpectedly".impossibile caricare il file utilizzando NSURLSession dati modulo in più parti in iOS

Requisiti

  1. caricare un file video/immagini al server
  2. App dovrebbe sostenere arrivi di fondo (Continua il processo di caricamento, anche dopo applicazione va in fondo)
  3. Server prevede i dati siano inviato utilizzando dati di moduli multiparte.

Metodi/API utilizzate per raggiungere questo

  1. NSURLSession sfondo sessione API (completo del codice di seguito elencati)

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

Sfide/Problemi di fronte

  1. fronte di errore "stream ended unexpectedly" ogni volta che sto usando questa API per processo di caricamento

Punti da notare

  1. Il caricamento sta ottenendo successo con lo stesso codice se uso NSURLConnection anziché NSURLSession.

  2. NSURLSession processo di caricamento in background si aspetta che il percorso del file (NSURL) come parametro, non accetta NSData. Non ci consente di convertire il file in NSData prima di caricarlo, ad esempio, non possiamo aggiungere NSData al corpo del file.

bisogno di aiuto seguenti punti

  1. C'è qualche errore nel corpo formdata multipart che si sta formando (nota - Lo stesso codice sta lavorando con NSURLConnection)

  2. Dove sto sbagliando nel mio approccio?

  3. È necessario apportare modifiche a livello di server per supportare i caricamenti NSURLSession backgroundSession? (nell'analisi dei dati o qualcos'altro?)

    Qui è il codice che viene utilizzato per il caricamento di un file

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

Lei sembra di impostare "Content Scrivi "due volte. Non sono sicuro di come funzioni. Non sono sicuro del resto. Faccio qualcosa di simile, ma creo il buffer di caricamento separato (in una funzione C++) e aggiungo solo il buffer dei buchi. Quindi, non ho molto di più per contribuire con. –

risposta

9

Non stai caricando ciò che pensi di essere. Il tuo intento è che i dati del corpo siano caricati così com'è. Invece, quando si chiama uploadTaskWithRequest:fromFile:, questo metodo annulla efficacemente tutti i valori HTTPBody o HTTPBodyStream nella richiesta e li sostituisce con il contenuto dell'URL passato tramite il parametro fromFile:.

Quindi, a meno che non si scriva da qualche parte quel blocco di dati del corpo con codifica del modulo all'URL del file, si sta caricando il file da solo anziché i dati del modulo multipart.

È necessario modificare il codice per scrivere i dati del modulo in un file invece di memorizzarlo in HTTPBody, quindi passare l'URL di quel file al parametro fromFile:.

+0

Si prega di fornire uno snippet di codice, grazie. –

+0

1. Cambia da File: a fromData :, e passa il valore di 'body'. – dgatwood

+0

2. Decommentazione // [appenddata del corpo: self.dataToPost]; e modificare self.dataToPost in [NSData dataWithContentsOfURL: self.videoURL]. – dgatwood

4

Per evitare perdite di tempo.

Il frammento completa in base alla risposta @dgatwood

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

E .. non dimenticare di aggiungere le intestazioni su richiesta oggetto come

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