iOS网络请求之ASI与AFN的二次封装及意义

引言

iOS9.0之后,NSURLConnection被苹果抛弃,该来的即便是迟些,但最终肯定会来。对于迷恋NSURLConnection还要适配iOS低版本的公司,就不得不三思了,当然,使用NSURLSession也是不错的,但面对成熟的ASI和AFN,我们更有理由选择。

正题

开始看到这个题目,很多人会有疑问:ASI和AFN都是很成熟的三方库,为什么要再次封装呢?
对此,我的理解是,对于咨讯、新闻类APP,或许不需要,它们主要以刷流量为主,直接使用(很适合我们抓包拿来练手)。但对于安全性要求较高的APP而言,它们需要的是有效流量,这时一般要对自己的URL进行加密,比如:“支付”类、会员视频点播等。如果URL加密的话,对ASI或AFN二次封装就要提上日程啦,当然这也是对其进行二次封装的作用及意义所在。

URL加密

我们采用方式比较简易,在URL的head中,添加动态token及User-Agent添加des加密字符的方式等,起到加密效果。

引入ASI和AFN SDK(最终项目选其一)

本人使用CocoaPods三方库管理工具

platform :ios,’7.0’
target ‘MMBao_master’ do

pod 'ASIHTTPRequest'
pod 'AFNetworking', '~> 3.0'
......
end

一、ASIHTTPRequest再封装

ASIHTTPRequest GitHub链接

1、ASIHTTPRequest异步请求及ASIHTTPRequestDelegate简析

ASI是iOS知名度最高的网络请求三方库,由于它的实现是基于底层的CFNetwork框架,运行效率较其他网络请求库都要高出一筹。
ASIHTTPRequest异步请求

(1)创建网络请求

NSURL *url = [NSURL URLWithString:@"http://192.168.1.111:8080/ProjectName/getToken];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url]; 
request.timeOutSeconds = 30; // 超时设置

(2)统一为请求添加head,如:Date 提供日期和时间标志、Content-Length请求内容的长度、Content-Type请求与实体对应的MIME信息等;或者添加自定义header的类型,比如特定用户标记信息,加密信息token等。

[request addRequestHeader:@"phone_type" value:@"iOS"];
[manager.requestSerializer setValue:tokenDes forHTTPHeaderField:@"token"];

......
(3)设置ASIHTTPRequestDelegate代理

request.delegate = self;  

(4)发送异步请求

[request startAsynchronous]; 

ASIHTTPRequestDelegate简析

(1)网络请求start
- (void)requestStarted:(ASIHTTPRequest *)request
(2)开始接收到服务器的数据
- (void)request:(ASIHTTPRequest *)request didReceiveData:(NSData *)data
(3)请求成功完毕
- (void)requestFinished:(ASIHTTPRequest *)request
(4)请求失败
- (void)requestFailed:(ASIHTTPRequest *)request
(5)取消请求,切记

[request clearDelegatesAndCancel];
2、EVNASIConnectionUtil工具类实现

EVNASIConnectionUtil.h

//
//  EVNASIConnectionUtil.h
//  MMBao_master
//
//  Created by developer on 16/8/24.
//  Copyright © 2016年 仁伯安. All rights reserved.
//

#import 
#import "ASIHTTPRequest.h"

#pragma mark - 请求方法
typedef NS_ENUM(NSUInteger, ASIURLMethod)
{
    ASIPOST = 1,
    ASIGET = 2,
};

#pragma mark - TAG定义,命名规则: URL开头+模块名字+Tag
typedef NS_ENUM(NSUInteger, ASIURLTag)
{
#pragma mark: 账户管理
    ASIURLGetTokenTag,
#pragma mark - 登录及注册
    
#pragma mark:  三方登录

#pragma mark - 分类及热词搜索

#pragma mark - 买家模块
};

#pragma mark - 返回的Result
typedef NS_ENUM(NSUInteger, ASIResultCode)
{
    ASIRS_Success = 1,
    ASIRS_Error,
};

@protocol ASIHTTPConnectionDelegate 
@optional

@required
/**
 *  网络请求完成(包括数据返回成功、失败、接口超时)后的回调方法
 *
 *  @param dicRespon     网络请求后返回的JSON数据
 *  @param URLTag        网络请求的标识tag
 *  @param theResultCode 状态码,成功 && 失败
 *  @param res           网络请求返回的result,一般1表示请求成功,0表示请求失败
 *  @param message       提示信息
 *  @param failStatus    是否显示网络请求异常图片
 */
- (void)resultWithDic:(NSDictionary *)dicRespon urlTag:(ASIURLTag)URLTag isSuccess:(ASIResultCode)theResultCode Result:(int) res Message:(NSString *) message failImage:(int) failStatus;

@optional
- (void) resultWithString:(NSString *) str;

@end

#pragma mark - EVNASIConnectionUtil工具类
@interface EVNASIConnectionUtil : NSObject
{
    NSMutableData *_dtReviceData;
    int FailStatus;
}

@property (nonatomic, assign) id delegate;
@property (nonatomic, assign) ASIURLTag urlTag;
@property (nonatomic, strong) ASIHTTPRequest *conn;


/**
 *  网络请求初始化方法
 *
 *  @param theUrlTag   网络请求的标识tag
 *  @param theDelegate 网络请求代理
 *
 *  @return ASIHTTP实例
 */
- (instancetype)initWithURLTag:(ASIURLTag)theUrlTag delegate:(id)theDelegate;


/**
 *  common 网络请求
 *
 *  @param strUrl      URL服务器地址
 *  @param strPostBody body
 *  @param theMethod   网络请求方式,比如GET、POST
 */
- (void)getResultFromUrlString:(NSString *)strUrl postBody:(NSString *)strPostBody method:(ASIURLMethod)theMethod;


/**
 *  上传图片音频 网络请求
 *
 *  @param strUrl           URL服务器地址
 *  @param dicText          需要的参数,dicImage表示,strImageFileName表示
 *  @param dicImage         图片名字
 *  @param strImageFileName 服务器端文件的目录名
 *  @param avFile           音频类网络请求文件名
 */
- (void)getResultFromUrlString:(NSString *)strUrl dicText:(NSDictionary *)dicText dicImage:(NSDictionary *)dicImage imageFilename:(NSMutableArray *)strImageFileName WithAVFile:(NSString *) avFile;

/**
 *  网络请求结束,终止
 */
- (void)stopConnection;

#pragma mark -
- (void)getResultFromUrlString:(NSString *)strUrl postBody:(NSMutableArray *)strPostBodyArray postArg:(NSMutableArray *) argArray method:(ASIURLMethod)theMethod failImage:(int) faileSatatus;

@end

EVNASIConnectionUtil.m

//
//  EVNASIConnectionUtil.m
//  MMBao_master
//
//  Created by developer on 16/8/24.
//  Copyright © 2016年 仁伯安. All rights reserved.
//

#import "EVNASIConnectionUtil.h"
#import "AppDelegate.h"
#import "MCdes.h"

#import 
#define KEYPassWordMCdes @"加密字符"

@implementation EVNASIConnectionUtil
{
    AppDelegate *appDel;
    NSString *tokenDes;
}

- (instancetype)initWithURLTag:(ASIURLTag)theUrlTag delegate:(id)theDelegate
{
    self = [super init];
    if (self)
    {
        self.delegate = theDelegate;
        self.urlTag = theUrlTag;

        appDel = (AppDelegate *)[UIApplication sharedApplication].delegate;

        tokenDes = appDel.appToken;

        if([self validateString:tokenDes] == NO)
        {
            tokenDes = @"";
        }
    }

    return self;
}
// URL编码
- (NSString *)encodeToPercentEscapeString: (NSString *) input
{
    NSString *outputStr = (NSString *)     CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,  (CFStringRef)input, NULL,  (CFStringRef)@"!*'();:@=+$,/?%#[]", kCFStringEncodingUTF8));
    return outputStr;
}

- (void)getResultFromUrlString:(NSString *)strUrl postBody:(NSMutableArray *)strPostBodyArray postArg:(NSMutableArray *)argArray method:(ASIURLMethod)theMethod failImage:(int)faileSatatus
{
    FailStatus = faileSatatus;
    strUrl = [strUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSMutableString *strPostBody = [[NSMutableString alloc] initWithString:@""];
    for(NSInteger i=0;i
3、EVNASIConnectionUtil使用
#import "EVNConnectionUtil.h"

@interface GetTokenFailViewController : BaseViewController
{
    EVNASIConnectionUtil *conn;
}
......
// 使用
- (void) getTokenMethod
{
    conn = [[EVNASIConnectionUtil alloc] initWithURLTag:ASIURLGetTokenTag delegate:self];
    NSString *urlString = [NSString stringWithFormat:@"%@%@",URL_HOST,@"getToken.html"];
    [conn getResultFromUrlString:urlString postBody:nil postArg:nil method:EVNPOST failImage:0]; // 发起请求
}

- (void) resultWithDic:(NSDictionary *)dicRespon evnUrlTag:(ASIURLTag)URLTag isSuccess:(ASIResultCode)theResultCode Result:(int)res Message:(NSString *)message failImage:(int)failStatus
{
    if(URLTag == ASIURLGetTokenTag)
    {
        if(res == 1)
        {
            AppDelegate *appDel = (AppDelegate *)[UIApplication sharedApplication].delegate;
           appDel.appToken = [NSString stringWithFormat:@"%@",[dicRespon objectForKey:@"token"]];
        }
        else
        {
            [NSThread sleepForTimeInterval:0.5];
            [self getTokenMethod];
        }
    }
}

二、AFNetworking再封装

AFNetworking GitHub链接

1、AFNetworking异步请求及AFNetworking简析

为了迎合苹果API,AFNetworking3.0中删除了对NSURLConnection的支持,转而对NSURLSession封装使用。

(1)创建网络请求,设置接受数据类型

AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.requestSerializer.timeoutInterval = 10;
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
manager.responseSerializer = [AFJSONResponseSerializer serializer];

(2)统一为请求添加head,如:Date 提供日期和时间标志、Content-Length请求内容的长度、Content-Type请求与实体对应的MIME信息等;或者添加自定义header的类型,比如特定用户标记信息,加密信息token等。

[manager.requestSerializer setValue:tokenDes forHTTPHeaderField:@"token"];
......

(3)发起网络请求,GET、POST
GET方式

[self.manager GET:strUrl parameters:strPostBody progress:^(NSProgress * _Nonnull downloadProgress) {
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSLog(@"JSON: %@", responseObject);
        [[UIApplication sharedApplication]setNetworkActivityIndicatorVisible:NO];
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"Error: %@", error);
    }];

POST方式

[self.manager POST:strUrl parameters:strPostBody progress:^(NSProgress * _Nonnull uploadProgress) {
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSLog(@"JSON: %@", responseObject);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"Error: %@", error);
    }];
2、EVNAFNConnectionUtil工具类实现

EVNAFNConnectionUtil.h

//
//  EVNAFNConnectionUtil.h
//  MMBao_master
//
//  Created by developer on 16/8/24.
//  Copyright © 2016年 仁伯安. All rights reserved.
//

#import 
#import "AFNetworking.h"

#pragma mark - 请求方法
typedef NS_ENUM(NSUInteger, URLMethod)
{
    POST = 1,
    GET = 2,
};

#pragma mark - TAG定义,命名规则: URL开头+模块名字+Tag
typedef NS_ENUM(NSUInteger, URLTag)
{
#pragma mark: 账户管理
    URLGetTokenTag,
#pragma mark - 登录及注册

#pragma mark:  三方登录

};

#pragma mark - 返回的Result
typedef NS_ENUM(NSUInteger, ResultCode)
{
    RS_Success = 1,
    RS_Error,
};

@protocol AFNConnectionDelegate 
@optional

@required
/**
 *  网络请求完成(包括数据返回成功、失败、接口超时)后的回调方法
 *
 *  @param dicRespon     网络请求后返回的JSON数据
 *  @param URLTag        网络请求的标识tag
 *  @param theResultCode 状态码,成功 && 失败
 *  @param res           网络请求返回的result,一般1表示请求成功,0表示请求失败
 *  @param message       提示信息
 *  @param failStatus    是否显示网络请求异常图片
 */
- (void)resultWithDic:(NSDictionary *)dicRespon urlTag:(URLTag)URLTag isSuccess:(ResultCode)theResultCode Result:(int) res Message:(NSString *) message failImage:(int) failStatus;

@optional
- (void) resultWithString:(NSString *) str;

@end

#pragma mark - EVNAFNConnectionUtil工具类
@interface EVNAFNConnectionUtil : NSObject
{
    NSMutableData *_dtReviceData;
    int FailStatus;
}

@property (nonatomic, assign) id delegate;
@property (nonatomic, assign) URLTag urlTag;
@property (nonatomic, strong) AFHTTPSessionManager *manager;

/**
 *  网络请求初始化方法
 *
 *  @param theUrlTag   网络请求的标识tag
 *  @param theDelegate 网络请求代理
 *
 *  @return ASIHTTP实例
 */
- (instancetype)initWithURLTag:(URLTag)theUrlTag delegate:(id)theDelegate;


/**
 *  common 网络请求
 *
 *  @param strUrl      URL服务器地址
 *  @param strPostBody body
 *  @param theMethod   网络请求方式,比如GET、POST
 */
- (void)getResultFromUrlString:(NSString *)strUrl postBody:(NSString *)strPostBody method:(URLMethod)theMethod;

/**
 *  上传图片音频 网络请求
 *
 *  @param strUrl           URL服务器地址
 *  @param dicText          需要的参数,dicImage表示,strImageFileName表示
 *  @param dicImage         图片名字
 *  @param strImageFileName 服务器端文件的目录名
 *  @param avFile           音频类网络请求文件名
 */
- (void)getResultFromUrlString:(NSString *)strUrl dicText:(NSDictionary *)dicText dicImage:(NSDictionary *)dicImage imageFilename:(NSMutableArray *)strImageFileName WithAVFile:(NSString *) avFile;

/**
 *  网络请求结束,终止
 */
- (void)stopConnection;
#pragma mark - 
- (void)getResultFromUrlString:(NSString *)strUrl postBody:(NSMutableArray *)strPostBodyArray postArg:(NSMutableArray *) argArray method:(URLMethod)theMethod failImage:(int) faileSatatus;

@end

EVNAFNConnectionUtil.m

//
//  EVNAFNConnectionUtil.m
//  MMBao_master
//
//  Created by developer on 16/8/24.
//  Copyright © 2016年 仁伯安. All rights reserved.
//

#import "EVNAFNConnectionUtil.h"
#import "AppDelegate.h"
#import "MCdes.h"
#import 
#define KEYPassWordMCdes @"加密字符"
@implementation EVNAFNConnectionUtil
{
    AppDelegate *appDel;
    NSString *tokenDes;
}

- (instancetype)initWithURLTag:(URLTag)theUrlTag delegate:(id) theDelegate
{
    self = [super init];
    if (self)
    {
        self.delegate = theDelegate;
        self.urlTag = theUrlTag;
        appDel = (AppDelegate *)[UIApplication sharedApplication].delegate;
        tokenDes = appDel.appToken;
        if([self validateString:tokenDes] == NO)
        {
            tokenDes = @"";
        }
    }
    return self;
}
// URL编码
- (NSString *)encodeToPercentEscapeString: (NSString *) input
{
    NSString *outputStr = (NSString *) CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)input, NULL, (CFStringRef)@"!*'();:@=+$,/?%#[]", kCFStringEncodingUTF8));

    return outputStr;
}

- (void)getResultFromUrlString:(NSString *)strUrl postBody:(NSMutableArray *)strPostBodyArray postArg:(NSMutableArray *)argArray method:(URLMethod)theMethod failImage:(int)faileSatatus
{
    FailStatus = faileSatatus;
    strUrl = [strUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

    NSMutableString *strPostBody = [[NSMutableString alloc] initWithString:@""];
    for(NSInteger i=0;i
3、EVNAFNConnectionUtil使用
@interface GetTokenFailViewController : BaseViewController
{
    EVNAFNConnectionUtil *conn;
}
......
- (void) getTokenMethod
{
    conn = [[EVNAFNConnectionUtil alloc] initWithURLTag:URLGetTokenTag delegate:self];
    NSString *urlString = [NSString stringWithFormat:@"%@%@",URL_HOST_CHEN,@"token/getToken.html"];
    [conn getResultFromUrlString:urlString postBody:nil postArg:nil method:EVNPOST failImage:0];
}

- (void) resultWithDic:(NSDictionary *)dicRespon evnUrlTag:(EVNURLTag)URLTag isSuccess:(EVNResultCode)theResultCode Result:(int)res Message:(NSString *)message failImage:(int)failStatus
{
    if(URLTag == URLGetTokenTag)
    {
        if(res == 1)
        {
                AppDelegate *appDel = (AppDelegate *)[UIApplication sharedApplication].delegate;
                appDel.appToken = [NSString stringWithFormat:@"%@",[dicRespon objectForKey:@"token"]];
        }
        else
        {
              [NSThread sleepForTimeInterval:0.5];
              [self getTokenMethod];
        }
    }
}

三、补充

时间仓促,不足之处见谅。。。。。。

本文已在版权印备案,如需转载请在版权印获取授权。
获取版权

你可能感兴趣的:(iOS网络请求之ASI与AFN的二次封装及意义)