iOS相关的http网络请求再次封装

一般情况下用的较多的是GET、POST请求方式,先封装一个HttpManager类

.m相关的代码

#import "HttpManager.h"

 

NSString * const HttpTokenExpiredNotification = @"HttpTokenExpiredNotification";

 

@implementation HttpManager

 

+ (instancetype)sharedManager

{

    static HttpManager *_manager = nil;

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        _manager = [[HttpManager alloc] init];

    });

    return _manager;

}

 

- (instancetype)init

{

    self = [super init];

    if (self) {

        if (_afManager == nil)

        {

            _afManager = [AFHTTPSessionManager manager];

            _afManager.requestSerializer = [AFJSONRequestSerializer serializer];

            //设置返回格式

            _afManager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/html",@"text/json",@"text/javascript", @"text/plain",@"image/jpeg",@"image/png",@"image/jpg",nil];

            [_afManager.requestSerializer setValue:[KDSTool getIphoneType] forHTTPHeaderField:@"phoneName"];

            _afManager.securityPolicy = [self customSecurityPolicy];

            //超时时间

            [_afManager.requestSerializer setTimeoutInterval:20.f];

        }

    }

    return self;

}

 

-(void)createResErrorWithCode:(NSInteger)code{

    NSString *domain = @"请求返回错误";

    NSString *desc = [KDSHttpResOption httpResponseLocalizeWithCode:code];

    NSDictionary *userInfo = @{NSLocalizedDescriptionKey:desc };

    self.resError = [NSError errorWithDomain:domain

                                         code:code

                                     userInfo:userInfo];

    NSLog(@"--{Kaadas}--error333=%@",self.resError);

    

}

- (void)setToken:(NSString *)token

{

    _token = token;

    if (token)

    {

        [self.afManager.requestSerializer setValue:token forHTTPHeaderField:@"token"];

    }

}

 

- (AFSecurityPolicy *)customSecurityPolicy {

    //先导入证书

    NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"server" ofType:@"p12"];

    //证书的路径

    NSData *certData = [NSData dataWithContentsOfFile:cerPath];

    // AFSSLPinningModeNone 使用证书验证模式

    //这个模式表示不做SSL pinning,

    //只跟浏览器一样在系统的信任机构列表里验证服务端返回的证书。若证书是信任机构签发的就会通过,若是自己服务器生成的证书就不会通过。

    AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];

    NSSet *certificateSet  = [[NSSet alloc] initWithObjects:certData, nil];

    [securityPolicy setPinnedCertificates:certificateSet];

    //validatesDomainName 是否需要验证域名,默认为YES;

    //    securityPolicy.validatesDomainName = YES; // 关键语句1

    //假如证书的域名与你请求的域名不一致,需把该项设置为NO;如设成NO的话,即服务器使用其他可信任机构颁发的证书,也可以建立连接,这个非常危险,建议打开。

    //置为NO,主要用于这种情况:客户端请求的是子域名,而证书上的是另外一个域名。因为SSL证书上的域名是独立的,假如证书上注册的域名是www.google.com,那么mail.google.com是无法验证通过的;当然,有钱可以注册通配符的域名*.google.com,但这个还是比较贵的。

    //如置为NO,建议自己添加对应域名的校验逻辑。

    securityPolicy.validatesDomainName = NO; // 关键语句1

    // allowInvalidCertificates 是否允许无效证书(也就是自建的证书),默认为NO

    //    securityPolicy.allowInvalidCertificates = NO; // 关键语句2

    // 如果是需要验证自建证书,需要设置为YES

    securityPolicy.allowInvalidCertificates = YES; // 关键语句2

    return securityPolicy;

}

 

- (NSMutableDictionary *)filteredDictionaryWithDictionary:(NSDictionary *)dictionary

{

    if (![dictionary isKindOfClass:NSDictionary.class]) return [NSMutableDictionary dictionary];

    NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:dictionary];

    for (NSString *key in dict.allKeys)

    {

        if ([dict[key] isKindOfClass:NSNull.class]) dict[key] = nil;

    }

    return dict;

}

 

- (NSURLSessionDataTask *)GET:(NSString *)URLString parameters:(id)parameters success:(void (^)(id _Nullable))success error:(void (^)(NSError * _Nonnull))errorBlock failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure

{

    if (![NSURL URLWithString:URLString].scheme)

    {

        URLString = [kBaseURL stringByAppendingString:URLString];

 

    }

    if (![NSURL URLWithString:URLString])

    {

        URLString = [URLString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];

    }

    return [self.afManager GET:URLString parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {

        [self parseObject:responseObject success:^(id  _Nullable data) {

            !success ?: success(data);

        } error:^(NSError *error) {

            !errorBlock ?: errorBlock(error);

        }];

    } failure:failure];

}

 

- (NSURLSessionDataTask *)POST:(NSString *)URLString parameters:(id)parameters success:(void (^)(id _Nullable))success error:(void (^)(NSError * _Nonnull))errorBlock failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure

{

    NSLog(@"--{Kaadas}--parameters=%@",parameters);

    if (![NSURL URLWithString:URLString].scheme)

    {

        URLString = [kBaseURL stringByAppendingString:URLString];

    }

    if (![NSURL URLWithString:URLString])

    {

        URLString = [URLString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];

    }

    return [self.afManager POST:URLString parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {

        [self parseObject:responseObject success:^(id  _Nullable data) {

            NSLog(@"--{Kaadas}--URLString=%@ result=%@",URLString,data);

            !success ?: success(data);

        } error:^(NSError *error) {

            NSLog(@"--{Kaadas}--error111=%@",error);

            if (error) {

                NSLog(@"--{Kaadas}--error222=%ld",(long)error.code);

                [self createResErrorWithCode:error.code];

                NSMutableDictionary *info = [NSMutableDictionary dictionaryWithDictionary:self.resError.userInfo];

                for (NSString *key in error.userInfo.allKeys)

                {

                    info[key] = error.userInfo[key];

                }

                error = [NSError errorWithDomain:self.resError.domain code:self.resError.code userInfo:info];

                !errorBlock ?: errorBlock(error);

            }

        }];

    } failure:failure];

}

 

/**

*@abstract 从服务器返回的解析完毕的字典中提取code、data和msg字段。

 

*@param obj 解析对象。

*@param success 成功回调,参数是data字段,如果没有也可能为空。

*@param error 失败回调。

*/

- (void)parseObject:(NSDictionary *)obj success:(nullable void (^)(id _Nullable data))success error:(void (^)(NSError *error))error

{

    NSLog(@"--{Kaadas}--解析对象obj=%@",obj);

 

    if (![obj isKindOfClass:[NSDictionary class]])

    {

        error([NSError errorWithDomain:@"返回值不正确" code:(NSInteger)KDSHttpErrorReturnValueIncorrect userInfo:nil]);

        return;

    }

    NSInteger code = [obj[@"code"] isKindOfClass:NSString.class] ? [obj[@"code"] intValue] : (NSInteger)KDSHttpErrorReturnValueIncorrect;

    ![obj[@"nowTime"] isKindOfClass:NSNumber.class] ?: (void)(_serverTime = [obj[@"nowTime"] doubleValue]);

    if (code == 200)

    {

        success(obj[@"data"]);

 

//        NSLog(@"--{Kaadas}--HTTPServerTime=%f",_serverTime);

    }

    else if (code == 444)

    {//failure的状态码401也表示token过期。

        

//        error([NSError errorWithDomain:[obj[@"msg"] isKindOfClass:NSString.class] ? obj[@"msg"] : @"token过期" code:code userInfo:nil]);

        [[NSNotificationCenter defaultCenter] postNotificationName:KDSHttpTokenExpiredNotification object:nil];

    }

    else

    {

        error([NSError errorWithDomain:[obj[@"msg"] isKindOfClass:NSString.class] ? obj[@"msg"] : @"未知错误" code:code userInfo:obj]);

    }

}

.h相关的代码

#import

#import "AFNetworking.h"

#import "HttpResOption.h"

///这里只定义一些未知错误。

typedef NS_ENUM(NSInteger, HttpError) {

    ///服务器返回的值不正确,例如本应该返回字典却返回字符串等。

    HttpErrorReturnValueIncorrect = 9999,

    ///调用方法时传入的参数错误,例如传入参数要求非空却传入一个空的值。

    HttpErrorParamIncorrect = 9998,

};

 

NS_ASSUME_NONNULL_BEGIN

 

@interface HttpManager : NSObject

 

+ (instancetype)sharedManager;

 

///请求和响应序列化都设置为JSON的AF请求类。

@property (nonatomic, strong, readonly) AFHTTPSessionManager *afManager;

///登录的token,由使用者赋值。

@property (nonatomic, strong, nullable) NSString *token;

///安全政策。

@property (nonatomic, strong, readonly) AFSecurityPolicy *customSecurityPolicy;

///服务器当前时间,距70年的本地时间秒数。

@property (nonatomic, assign, readonly) NSTimeInterval serverTime;

//自定义NSError

@property(nonatomic,strong)NSError *resError;

/**

*@abstract 过滤掉原字典中的NSNull值。

*@param dictionary 原字典。

*@return 过滤掉原字典中的NSNull(删掉值为NSNull的key)值后返回的新的可变字典,如果传入的参数不是字典,会返回空字典。

*/

- (NSMutableDictionary *)filteredDictionaryWithDictionary:(NSDictionary *)dictionary;

 

/**

Creates and runs an `NSURLSessionDataTask` with a `GET` request.

 

@param URLString The URL string used to create the request URL.如果是全路径则不会改变,否则加上统一的前缀。

@param parameters The parameters to be encoded according to the client request serializer.

@param success A block object to be executed when the task finishes successfully, 即服务器返回200. This block has no return value and one argument: responseObject是返回字典中的data字段的值。

@param errorBlock 当服务器返回数据被正确解析后,返回字典的code字段不是200,则会执行这个回调,error的code是字典的code的值,domain直接放字典的msg信息。

@param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred.

 

@see -dataTaskWithRequest:completionHandler:

*/

- (nullable NSURLSessionDataTask *)GET:(NSString *)URLString

                            parameters:(nullable id)parameters

                               success:(nullable void (^)(id _Nullable responseObject))success

                                 error:(nullable void (^)(NSError *error))errorBlock

                               failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;

 

/**

Creates and runs an `NSURLSessionDataTask` with a `POST` request.

 

@param URLString The URL string used to create the request URL.如果是全路径则不会改变,否则加上统一的前缀。

@param parameters The parameters to be encoded according to the client request serializer.

@param success A block object to be executed when the task finishes successfully, 即服务器返回200. This block has no return value and takes one argument: responseObject是返回字典中的data字段的值。

@param errorBlock When received response from server, if code wasn't 200, there might be an error occurred. So, the userInfo of the block's error param may contain response data optionally.

@param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred.

 

@see -dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:

*/

- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString

                             parameters:(nullable id)parameters

                                success:(nullable void (^)(id _Nullable responseObject))success

                                error:(nullable void (^)(NSError *error))errorBlock

                                failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;

 

#pragma mark - 通知相关

/** 登录后保存的token过期了,需要退出登录后重新登录。 */

FOUNDATION_EXTERN NSString * const HttpTokenExpiredNotification;

 

@end

 

在用到的地方二次封装就可以了

例如login里面的登录接口:

.h里面的实现

/**

*@abstract 登录接口。

*@param source 登录源,手机(1),邮箱(2)。

*@param name 登录用户名。如果是手机号注册,手机号前必须加上国家/地区码,如8613500010086.

*@param pwd 登录密码。

*@param success 成功回调。

*@param errorBlock 服务器返回错误时的回调,参数error的code是服务器返回的code,domain是服务器返回的msg。

*@param failure 由于数据解析及网络等原因失败的回调,error是系统传递过来的。

*@return 当前的请求任务。

*/

- (nullable NSURLSessionDataTask *)login:(int)source username:(NSString *)name password:(NSString *)pwd success:(nullable void(^)(KDSUser *user))success error:(nullable void(^)(NSError *error))errorBlock failure:(nullable void(^)(NSError *error))failure;

.m里面的代码实现

- (NSURLSessionDataTask *)login:(int)source username:(NSString *)name password:(NSString *)pwd success:(void (^)(KDSUser * _Nonnull))success error:(void (^)(NSError * _Nonnull))errorBlock failure:(void (^)(NSError * _Nonnull))failure

{

    name = name ?: @""; pwd = pwd ?: @"";

    NSString *url = source == 1 ? @"user/login/getuserbytel" : @"user/login/getuserbymail";

    NSDictionary *params = @{(source == 1 ? @"tel" : @"mail"):name, @"password":pwd};

    return [self POST:url parameters:params success:^(id  _Nullable responseObject) {

        if (![responseObject isKindOfClass:NSDictionary.class])

        {

            !errorBlock ?: errorBlock([NSError errorWithDomain:@"返回参数不正确" code:9999 userInfo:nil]);

            return;

        }

        //成功服务器共返回4个键值对,meUsername 、 mePwd 、 uid 、 token,所有值都是哈希过的。

        NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:responseObject];

//        NSLog(@"--{Kaadas}--dict===%@",dict);

        

        for (NSString *key in dict.allKeys)

        {

            if (![dict[key] isKindOfClass:NSString.class]) dict[key] = nil;

        }

        KDSUser *user = [[KDSUser alloc] init];

        user.name = name;

        user.username = dict[@"meUsername"];

        user.uid = dict[@"uid"];

        user.password = dict[@"mePwd"];

        user.token = dict[@"token"];

        self.token = dict[@"token"];

        //商城token

        if(dict[@"storeToken"]){

            [userDefaults setObject:dict[@"storeToken"] forKey:USER_TOKEN];

            [userDefaults synchronize];

        }

        

        !success ?: success(user);

    } error:errorBlock failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {

        !failure ?: failure(error);

    }];

}

你可能感兴趣的:(iOS相关的http网络请求再次封装)