转载请注明出处:http://blog.csdn.net/dengbin9009/article/details/43304813
前文有提到在初始化的时候可以设置Http的头信息,这没有任何问题,但是在笔者使用过程中,时常是要获取Http返回的一些头信息,在初次用AFNetworking2.0新特性NSURLSessionDataTask的时候,为了获取返回的头信息,搞了两个晚上,先是度娘,谷歌,StackOverflow,然后各种那个群找人,嘴壶问同事找大神,最后都说没有用过。就在想要放弃,想跟服务端沟通,不要把必要信息放在头信息中得时候,忽然灵感忽现:
再此讲述一下解决过程和最后的解决方法。
用过AFNetworking2.0 中NSURLSessionDataTask的朋友都知道,大概一个请求方式会类似于下面的方法(由于代码是从程序中直接拷出来的,所有直接使用会报错,请见谅)
- (NSURLSessionDataTask *)requestUpdateScheduleWithParam:(NSArray *)param success:(void (^)(NSString *))success failure:(void (^)(NSString *))failure{ NSError *parseError = nil; //NSDictionary转换为Data NSData* jsonData = [NSJSONSerialization dataWithJSONObject:param options:NSJSONWritingPrettyPrinted error:&parseError]; //Data转换为JSON NSString* str = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; NSDictionary *dic = @{@"param": str}; NSURLSessionDataTask *task = [self POST:UpdateScheduleRequest parameters:dic success:^(NSURLSessionDataTask *task, id responseObject) { NSInteger result = [responseObject[@"result"] integerValue]; if ( result == 0 ) { success(@"true"); } else { NSString *message = responseObject[@"message"]; failure(message); } } failure:^(NSURLSessionDataTask *task, NSError *error) { DLog(@"%@",error.localizedDescription); failure(error.localizedDescription); }]; return task; }
在返回的结果中我们能够取到的返回数据只有三种:
1、NSURLSessionDataTask *task 返回的和此次请求有关的描述
2、id responseObject AFNetworking帮助自动格式化后的结果,与上文初始化HttpClient时默认的responseSerializer对应
3、NSError *error AFNetworking内部报错,网络请求不通的或者数据解析错误等
上面所描述的三种数据中 responseObject和error显然是不可行的,所以只有在task中寻找希望,所以详细查看类NSURLSessionDataTask
发现其中只是简单继承于 NSURLSessionTask,于是继续进入NSURLSessionTask观察:
会看到其中有个属性:
@property (readonly, copy) NSURLResponse *response; /* may be nil if no response has been received */
这个似乎很接近我们需要的结果,因为往往response中都会包含我们所需要的头信息。然后继续往下查看NSURLResponse的信息。
结果在其中只有寥寥数条属性,关键的是没有我们想要的Header信息(代码篇幅略长,所以删除了一些注释)!
@interface NSURLResponse : NSObject <NSSecureCoding, NSCopying> { @package NSURLResponseInternal *_internal; } /*! @method initWithURL:MIMEType:expectedContentLength:textEncodingName: @abstract Initialize an NSURLResponse with the provided values. @param URL the URL @param MIMETYPE the MIME content type of the response @param expectedContentLength the expected content length of the associated data @param textEncodingName the name of the text encoding for the associated data, if applicable, else nil @result The initialized NSURLResponse. @discussion This is the designated initializer for NSURLResponse. */ - (instancetype)initWithURL:(NSURL *)URL MIMEType:(NSString *)MIMEType expectedContentLength:(NSInteger)length textEncodingName:(NSString *)name; @property (readonly, copy) NSURL *URL; @property (readonly, copy) NSString *MIMEType; @property (readonly) long long expectedContentLength; @property (readonly, copy) NSString *textEncodingName; @property (readonly, copy) NSString *suggestedFilename; @end
这可如何是好!!!希望似乎就此破灭,仿佛看到服务端的大哥大姐投来的鄙视的眼神于吐槽(#¥%#¥……%……¥#@¥#@%¥#……此处省略数万字)
但是!在NSURLResponse中继续往下看,可以看到NSURLResponse的一个子类NSHTTPURLResponse,在这个子类中竟然有看着很像的的一个属性。
/*! @method allHeaderFields @abstract Returns a dictionary containing all the HTTP header fields of the receiver. @discussion By examining this header dictionary, clients can see the "raw" header information which was reported to the protocol implementation by the HTTP server. This may be of use to sophisticated or special-purpose HTTP clients. @result A dictionary containing all the HTTP header fields of the receiver. */ @property (readonly, copy) NSDictionary *allHeaderFields;
恩,对,这个属性看起来基友可能(因为在使用AFHTTPRequestOperation请求数据的时候,其中也有个NSHTTPURLResponse,同样的也是在allHeaderFields中取到头信息)
但是在NSURLSessionTask中只有NSURLResponse *response而没有NSHTTPURLResponse *response!父类又不能使用子类中得属性。再次开始纠结!
结果抱着试试看的心理将NSURLResponse *response强制转换成NSHTTPURLResponse,结果TMD竟然可以!
- (NSURLSessionDataTask *)requestLoginWithUsername:(NSString *)username password:(NSString *)password success:(void (^)(NSString *,LoginDetailsDataModel *))success failure:(void (^)(NSString *))failure{ NSDictionary *dic = @{@"username": username, @"password":[self md5:password]}; NSURLSessionDataTask *task = [self GET:LoginRequest parameters:dic success:^(NSURLSessionDataTask *task, id responseObject) { LoginDataModel *loginSuccessDataModel = [[LoginDataModel alloc] initWithDictionary:responseObject]; NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response; <span style="color:#FF0000;">// 此处强制转换类型。</span> NSInteger result = [loginSuccessDataModel.result integerValue]; if ( result == 0 ) { success(response.allHeaderFields[@"sid"],loginSuccessDataModel.userInfo); } else { NSString *message = loginSuccessDataModel.message; DLog(@"%@",message); failure(message); } } failure:^(NSURLSessionDataTask *task, NSError *error) { DLog(@"%@",error.localizedDescription); failure(error.localizedDescription); }]; return task; }
最后问题解决。
这似乎是NSURLSessionDataTask本身的一个问题,希望以后可以得到解决。