obj-c AFNetworking 2.0 POST请求不起作用
您好想通过使用AFNetworking 2.0发送一些数据(string和文件)到服务器。 不知何故,POST请求(对于一个论坛)的数据是不正确的,它看起来像是在请求上的编码/序列化丢失。 由于服务器无法使用我上传的数据。
如何将编码/序列化设置为请求?
我假设URL表单参数编码,必须设置。 文档说明
[[AFHTTPRequestSerializer serializer] requestWithMethod:@"POST" URLString:URLString parameters:parameters];
我试图做到这一点,但我不知道如何做到这一点。 以下Xcode通过警告:
manager.requestSerializer = [[AFHTTPRequestSerializer serializer] requestWithMethod:@"POST" URLString:URLString parameters:parameters];
/…/CameraViewController.m:105:31:从“NSMutableURLRequest *”分配给“AFHTTPRequestSerializer *”的指针types不兼容
在我的源代码下面:
CameraViewController.h
#import <UIKit/UIKit.h> @interface CameraViewController : UIViewController <UIImagePickerControllerDelegate, UINavigationControllerDelegate> @property (weak, nonatomic) IBOutlet UIImageView *imageView; @end
CameraViewControllerView.m
#import "CameraViewController.h" #import "AFHTTPRequestOperationManager.h" @interface CameraViewController () @property (nonatomic) int photoIsTaken; @end @implementation CameraViewController // removed unecessary code for this question - (void)upload { NSLog(@"%s: uploader ", __FUNCTION__); AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; NSDictionary *parameters = @{@"latitude": @"8.444444", @"longitude": @"50.44444", @"location": @"New York", @"type": @"2", @"claim": @"NYC", @"flag": @"0", @"file": UIImageJPEGRepresentation(self.imageView.image,0.2)}; NSString *URLString = @"http://192.168.1.157/tapp/laravel/public/foobar/upload"; manager.requestSerializer = [[AFHTTPRequestSerializer serializer] requestWithMethod:@"POST" URLString:URLString parameters:parameters]; [manager POST:URLString parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) { NSLog(@"JSON: %@", responseObject); } failure:^(AFHTTPRequestOperation *operation, NSError *error) { NSLog(@"Error: %@, %@", error, operation.responseString); }]; [self dismissViewControllerAnimated:NO completion:nil]; } @end
最后它的工作。 是一个麻烦,但现在我真的很高兴…在我的testing过程中,我遇到了一些问题,在Wifi内请求身体stream枯竭,有什么奇怪的。
下面的代码,为我做了诡计。
- (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]; }
感谢@NobleK,一个类别可能是解决这个问题的最好方法。 这是一个示例代码:
@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
我一直在寻找一个好的答案,这个问题超过10个小时,终于抓住了一些什么工作! 根据苹果文件
NSURLErrorRequestBodyStreamExhausted(-1021)当需要正文stream但客户端不提供一个时返回。 这会影响使用正文stream发送POST请求的iOS客户端,但不会实现NSURLConnection委托方法连接:needNewBodyStream。
所以我不得不做的是子类AFHTTPRequestOperation并实现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
如果你想知道如何使用这个扩展类来上传多部分图像数据,这里是例子//.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]; }
希望这可以帮助那些正在遭受这个问题的人:)