AFNetworking 2.0获取响应头信息

转载请注明出处: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本身的一个问题,希望以后可以得到解决。






郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。