obj-c AFNetworking 2.0 POST 请求不起作用
Posted
技术标签:
【中文标题】obj-c AFNetworking 2.0 POST 请求不起作用【英文标题】:obj-c AFNetworking 2.0 POST request does not work 【发布时间】:2013-11-22 11:35:08 【问题描述】:您好想通过使用 AFNetworking 2.0 将一些数据(字符串和文件)发送到服务器。不知何故,POST请求的数据(对于forumlar)不正确,看起来请求上的编码/序列化丢失了。由于服务器无法处理我上传的数据。
如何设置请求的编码/序列化?
我假设必须设置 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 *'
在我的源代码下面:
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
【问题讨论】:
你真的要发送嵌入在 url 中的整个图像吗? 我想通过 POST 请求发送图像,作为普通公式上传。该解决方案可以在 AFN 1.3 中轻松运行。所以我认为这是要走的路,但 AFN 2.0 的行为不同。会试试你的小费。文件不是总是作为 POST 请求中的参数发送吗? 图像应该进入正文。想一想,这就像您将一个潜在的 url >1MB 粘贴到您的浏览器 URL 栏中! @ErikKerber mulitpart 为我解决了问题。对于文档,我添加了一个 anwser。 【参考方案1】:终于成功了。很麻烦,但现在我真的很高兴......在我的测试过程中,我在 Wifi 中遇到了一些“请求体流耗尽”的问题,这很奇怪。
下面的代码对我有用。
- (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];
【讨论】:
嗨,如果你不是我的:目前我正在使用 php 服务器,我想知道“ [manager.requestSerializer setAuthorizationHeaderFieldWithUsername:@"foo" password:@"bar"]; " -- > 这是什么意思?我可以从哪里获得这些凭据 如果可以的话,能否请您在这里发布一些适合上述代码的PHP代码 @MannamBrahmam 使用$_POST 变量在您的服务器上获取发布的参数。例如。var_dump($_POST);
【参考方案2】:
感谢@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
【讨论】:
这是迄今为止该问题的最佳解决方案。令人惊讶的是,这不是 AFNetworking 的一部分。【参考方案3】:10 多个小时以来,我一直在为这个地狱般的问题寻找好的答案,终于找到了可行的方法!根据 Apple Doc
NSURLErrorRequestBodyStreamExhausted (-1021) 当需要正文流但客户端未提供时返回。这会影响 ios 上使用正文流发送 POST 请求但未实现 NSURLConnection 委托方法 connection: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];
希望这可以帮助那些遭受此问题的人:)
【讨论】:
感谢您提供此解决方案。它终于解决了我的问题。但是我选择了一种更简单的方法。我没有对AFHTTPRequestOperation
进行子类化,而是在其上创建了一个包含connection:needNewBodyStream
方法的类别。这就是所有需要的。我的其余代码保持不变。以上是关于obj-c AFNetworking 2.0 POST 请求不起作用的主要内容,如果未能解决你的问题,请参考以下文章
从 AFNetworking 1.3 迁移到 AFNetworking 2.0 的问题