AFNetworking 2.0 multipart request body blank

前端 未结 3 931
伪装坚强ぢ
伪装坚强ぢ 2021-02-10 00:47

Similar to this issue.

Using AFNetworking 2.0.3 and trying to upload an image using AFHTTPSessionManager\'s POST + constructingBodyWithBlock. For reasons unknown, it se

3条回答
  •  攒了一身酷
    2021-02-10 01:07

    Rob is absolutely right, the problem you're seeing is related to the (now closed) issue 1398. However, I wanted to provide a quick tl;dr in case anyone else was looking.

    First, here's a code snippet provided by gberginc on github that you can model your file uploads after:

    NSString* apiUrl = @"http://example.com/upload";
    
    // Prepare a temporary file to store the multipart request prior to sending it to the server due to an alleged
    // bug in NSURLSessionTask.
    NSString* tmpFilename = [NSString stringWithFormat:@"%f", [NSDate timeIntervalSinceReferenceDate]];
    NSURL* tmpFileUrl = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:tmpFilename]];
    
    // Create a multipart form request.
    NSMutableURLRequest *multipartRequest = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST"
                                                                                                       URLString:apiUrl
                                                                                                      parameters:nil constructingBodyWithBlock:^(id formData)
                                             {
                                                 [formData appendPartWithFileURL:[NSURL fileURLWithPath:filePath]
                                                                            name:@"file"
                                                                        fileName:fileName
                                                                        mimeType:@"image/jpeg" error:nil];
                                             } error:nil];
    
    // Dump multipart request into the temporary file.
    [[AFHTTPRequestSerializer serializer] requestWithMultipartFormRequest:multipartRequest
                                              writingStreamContentsToFile:tmpFileUrl
                                                        completionHandler:^(NSError *error) {
                                                            // Once the multipart form is serialized into a temporary file, we can initialize
                                                            // the actual HTTP request using session manager.
    
                                                            // Create default session manager.
                                                            AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
    
                                                            // Show progress.
                                                            NSProgress *progress = nil;
                                                            // Here note that we are submitting the initial multipart request. We are, however,
                                                            // forcing the body stream to be read from the temporary file.
                                                            NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithRequest:multipartRequest
                                                                                                                       fromFile:tmpFileUrl
                                                                                                                       progress:&progress
                                                                                                              completionHandler:^(NSURLResponse *response, id responseObject, NSError *error)
                                                                                                  {
                                                                                                      // Cleanup: remove temporary file.
                                                                                                      [[NSFileManager defaultManager] removeItemAtURL:tmpFileUrl error:nil];
    
                                                                                                      // Do something with the result.
                                                                                                      if (error) {
                                                                                                          NSLog(@"Error: %@", error);
                                                                                                      } else {
                                                                                                          NSLog(@"Success: %@", responseObject);
                                                                                                      }
                                                                                                  }];
    
                                                            // Add the observer monitoring the upload progress.
                                                            [progress addObserver:self
                                                                       forKeyPath:@"fractionCompleted"
                                                                          options:NSKeyValueObservingOptionNew
                                                                          context:NULL];
    
                                                            // Start the file upload.
                                                            [uploadTask resume];
                                                        }];
    

    And secondly, to summarize the problem (and why you have to use a temporary file as a work around), it really is two fold.

    1. Apple considers the content-length header to be under its control, and when a HTTP body stream is set for a NSURLRequest Apple's libraries will set the encoding to Chunked and then abandon that header (and thereby clearing any content-length value AFNetworking sets)
    2. The server the upload is hitting doesn't support Transfer-Encoding: Chunked (eg. S3)

    But it turns out, if you're uploading a request from a file (because the total request size is known ahead of time), Apple's libraries will properly set the content-length header. Crazy right?

提交回复
热议问题