obj-c AFNetworking 2.0 POST request does not work

前端 未结 3 1417
面向向阳花
面向向阳花 2020-12-08 17:38

Hi want to send some data (strings and a file) to a server, by using AFNetworking 2.0. Somehow the data for the POST request (for a forumlar) ist not correct, it looks like

相关标签:
3条回答
  • 2020-12-08 18:09

    I have been looking for good answer for this one hell of a problem more than 10 hours and finally get hold of something what would work! according to Apple Doc

    NSURLErrorRequestBodyStreamExhausted (-1021) Returned when a body stream is needed but the client does not provide one. This impacts clients on iOS that send a POST request using a body stream but do not implement the NSURLConnection delegate method connection:needNewBodyStream.

    so what I had to do is subclass AFHTTPRequestOperation and implement all the delegate methods for NSURLConnection //.h

        @interface CGHTTPRequestOperation : AFHTTPRequestOperation
    
        @end
    

    //.m

        @implementation CGHTTPRequestOperation
    
        #pragma mark NSURLConnection delegate methods
    
        - (NSInputStream *)connection:(NSURLConnection __unused *)connection needNewBodyStream:(NSURLRequest *)request {
    
            if ([request.HTTPBodyStream conformsToProtocol:@protocol(NSCopying)]) {
    
                return [request.HTTPBodyStream copy];
    
            }
    
            return nil;
    
        }
    
        - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
            [super connection:connection didReceiveResponse:response];
        }
    
        - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
            [super connection:connection didReceiveData:data];
        }
    
        - (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite {
            [super connection:connection didSendBodyData:bytesWritten totalBytesWritten:totalBytesWritten totalBytesExpectedToWrite:totalBytesExpectedToWrite];
        }
    
        - (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse{
            return [super connection:connection willCacheResponse:cachedResponse];
        }
    
        - (void)connectionDidFinishLoading:(NSURLConnection *)connection{
            [super connectionDidFinishLoading:connection];
        }
    
        - (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
            [super connection:connection didFailWithError:error];
        }
    
        - (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection {
            return YES;
        }
        - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
            [super connection:connection willSendRequestForAuthenticationChallenge:challenge];
        }
    
        @end
    

    If you wonder how to use this extended classes in regards to upload the multi-part image data here is the example //.h

        typedef enum {
    
            CGFileUploadStatusError = 0,
            CGFileUploadStatusSuccess = 1,
    
        } CGFileUploadStatus;
    
        typedef void(^CGNetworkingFileUploadCBlock) (CGFileUploadStatus status,NSString *responseString);
    

    //.m

        + (void) uploadImageAtPath:(NSString *) imagePath cBlock:(CGNetworkingFileUploadCBlock) cBlock {
    
            AFHTTPRequestSerializer *r = [AFHTTPRequestSerializer serializer];
    
            NSDictionary *param = @{@"param1":@"",@"param2":@""};
            NSData *d = [NSData dataWithContentsOfFile:imagePath];
    
            __block NSString *paramNameForImage = [imagePath pathComponents].lastObject;
    
            NSError *error = nil;
            NSMutableURLRequest *urlRequest = [r multipartFormRequestWithMethod:@"POST" URLString:@"http://url_to_up_load_image" parameters:param constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
    
                    [formData appendPartWithFileData:d name:@"FileUploadControl" fileName:paramNameForImage mimeType:@"image/jpeg"];
    
                } error:&error];
    
                if (error) {
    
                    NSLog(@"Some error:%@",error);
    
                }
    
    
    
            CGHTTPRequestOperation *requestOperation = [[CGHTTPRequestOperation alloc] initWithRequest:urlRequest];
    
    
            //[requestOperation setCredential:nil]; //set cred here
            //[requestOperation setSecurityPolicy:nil]; //set security policy here if you are using one
    
            [requestOperation setResponseSerializer:[AFHTTPResponseSerializer serializer]];
    
            [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    
                NSLog(@"Success: %@ ***** %@", operation.responseString, operation.response.allHeaderFields);
                cBlock(CGFileUploadStatusSuccess,operation.responseString);
    
            } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    
                NSLog(@"Error: %@ ***** %@", operation, error);
                cBlock(CGFileUploadStatusError,operation.responseString);
    
            }];
    
    
            [requestOperation setUploadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) {
    
    
            }];
    
    
            [requestOperation start];
            [requestOperation waitUntilFinished];
    
        }
    

    Hope this helps those who is suffering this problem :)

    0 讨论(0)
  • 2020-12-08 18:14

    Finally it works. Was a hassle but now I am really happy... During my testing I had some problems with 'request body stream exhausted' within Wifi, what was strange.

    Below the code that did the trick for me.

    - (void)upload {
    
        // !!! only JPG, PNG not covered! Have to cover PNG as well
        NSString *fileName = [NSString stringWithFormat:@"%ld%c%c.jpg", (long)[[NSDate date] timeIntervalSince1970], arc4random_uniform(26) + 'a', arc4random_uniform(26) + 'a'];
        // NSLog(@"FileName == %@", fileName);
    
        AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
    
        NSDictionary *parameters = @{@"lat": @"8.444444",
                                     @"lng": @"50.44444",
                                     @"location": @"New York",
                                     @"type": @"2",
                                     @"claim": @"NYC",
                                     @"flag": @"0"};
         // BASIC AUTH (if you need):
        manager.securityPolicy.allowInvalidCertificates = YES;
        manager.requestSerializer = [AFHTTPRequestSerializer serializer];
        [manager.requestSerializer setAuthorizationHeaderFieldWithUsername:@"foo" password:@"bar"];
        // BASIC AUTH END
    
        NSString *URLString = @"http://192.168.1.157/tapp/laravel/public/foobar/upload";
    
        /// !!! only jpg, have to cover png as well
        NSData *imageData = UIImageJPEGRepresentation(self.imageView.image, 0.5); // image size ca. 50 KB
        [manager POST:URLString parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
            [formData appendPartWithFileData:imageData name:@"file" fileName:fileName mimeType:@"image/jpeg"];
        } success:^(AFHTTPRequestOperation *operation, id responseObject) {
            NSLog(@"Success %@", responseObject);
        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
            NSLog(@"Failure %@, %@", error, operation.responseString);
        }];
    
        [self dismissViewControllerAnimated:NO completion:nil];
    }
    
    0 讨论(0)
  • 2020-12-08 18:29

    Thanks @NobleK , a category may be the best way to fix this issue. Here is a sample code:

    @interface AFURLConnectionOperation (AuthenticationChallengeUploadFix)
    @end
    
    @implementation AFURLConnectionOperation (AuthenticationChallengeUploadFix)
    
    - (NSInputStream *)connection:(NSURLConnection __unused *)connection needNewBodyStream:(NSURLRequest *)request {
        if ([request.HTTPBodyStream conformsToProtocol:@protocol(NSCopying)]) {
            return [request.HTTPBodyStream copy];
        }
        return nil;
    }
    
    @end
    
    0 讨论(0)
提交回复
热议问题