【发布时间】:2014-07-29 09:52:00
【问题描述】:
如果我使用以下代码,我无法始终从服务器读取响应。
标题:
#import <Foundation/Foundation.h>
@interface TestHttpClient : NSObject<NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDownloadDelegate>
-(void)POST:(NSString*) relativePath payLoad:(NSData*)payLoad;
@end
实施:
#import "TestHttpClient.h"
@implementation TestHttpClient
-(void)POST:(NSString*)relativePath payLoad:(NSData*)payLoad
{
NSURL* url = [NSURL URLWithString:@"http://apps01.ditat.net/mobile/batch"];
// Set URL credentials and save to storage
NSURLCredential *credential = [NSURLCredential credentialWithUser:@"BadUser" password:@"BadPassword" persistence: NSURLCredentialPersistencePermanent];
NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc] initWithHost:[url host] port:443 protocol:[url scheme] realm:@"Ditat mobile services endpoint" authenticationMethod:NSURLAuthenticationMethodHTTPBasic];
[[NSURLCredentialStorage sharedCredentialStorage] setDefaultCredential:credential forProtectionSpace:protectionSpace];
// Configure session
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration ephemeralSessionConfiguration];
sessionConfig.timeoutIntervalForRequest = 30.0;
sessionConfig.timeoutIntervalForResource = 60.0;
sessionConfig.HTTPMaximumConnectionsPerHost = 1;
sessionConfig.URLCredentialStorage = [NSURLCredentialStorage sharedCredentialStorage]; // Should this line be here??
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:[NSOperationQueue mainQueue]];
// Create request object with parameters
NSMutableURLRequest *request =
[NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60.0];
// Set header data
[request setHTTPMethod:@"POST"];
[request setValue:@"application/x-protobuf" forHTTPHeaderField:@"Content-Type"];
[request setValue:@"Version 1.0" forHTTPHeaderField:@"User-Agent"];
[request setValue:@"Demo" forHTTPHeaderField:@"AccountId"];
[request setValue:@"1234-5678" forHTTPHeaderField:@"DeviceSerialNumber"];
[request setValue:@"iOS 7.1" forHTTPHeaderField:@"OSVersion"];
[request setHTTPBody:payLoad];
// Call session to post data to server??
NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request];
[downloadTask resume];
}
-(void)invokeDelegateWithResponse:(NSHTTPURLResponse *)response fileLocation:(NSURL*)location
{
NSLog(@"HttpClient.invokeDelegateWithResponse - code %ld", (long)[response statusCode]);
}
#pragma mark - NSURLSessionDownloadDelegate
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{
NSLog(@"NSURLSessionDownloadDelegate.didFinishDownloadingToURL");
[self invokeDelegateWithResponse:(NSHTTPURLResponse*)[downloadTask response] fileLocation:location];
[session invalidateAndCancel];
}
// Implemented as blank to avoid compiler warning
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
}
// Implemented as blank to avoid compiler warning
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes
{
}
可以从任何 VC 调用(例如在按钮操作下放置代码)
-(IBAction)buttonTouchUp:(UIButton *)sender
{
TestHttpClient *client = [[TestHttpClient alloc] init];
[client POST:@"" payLoad:nil];
return;
}
如果您启动程序并调用此代码 - 它会在 NSLog 完成中显示 401。第二次尝试 - 将不起作用。或者如果稍等一下可能会起作用。但它不会在您按下按钮时发送服务器请求。
NSURLSession 以某种方式“记住”失败的尝试并且不会返回任何内容?为什么会出现这种行为?每次按下按钮时,我都希望看到 2 条 NSLog 消息。
【问题讨论】:
-
您需要实现自己的包装器,还是可以使用现有的框架? AFNetworking 是个不错的选择。即使你不能使用它,你也可以在它的实现中找到答案。
-
AFNetworking 也是一个包装器,怀疑它是否能解决我的问题,只需添加另一层代码。我更喜欢自己弄清楚而不使用 3rd 方库,尤其是我所做的只是下载文件..我猜它以某种方式缓存了响应,我只需要编写某种强制清理..
-
就总是看到两个请求(而不仅仅是第一次)而言,这可能是因为您正在为每个请求创建一个新的
NSURLSession。您真的想创建一个NSURLSession并让后续请求使用同一个会话。 -
可能与您手头的问题无关,但您的
didReceiveChallenge应该有一个else条件,该条件使用NSURLSessionAuthChallengeCancelAuthenticationChallenge调用completionHandler。如果if语句失败,如果您根本不调用completionHandler,您当前的实现将停止。 -
Rob,我在单个请求中看到双打,这只是内置客户端的工作方式。我在 .NET 中看到它的行为相同
标签: ios nsurlsession