iOS网络请求策略——AFNetworking的基本使用

今天和大家一起来学习一下AFNetworking的基本使用,有疏忽的地方,还望各位不吝赐教。


一、AFNetworking的基本使用

1、控制器代码

#import "ViewController.h"
#import 
@interface ViewController ()

@end
/*
 * 在开发中进行二次封装可以简化步骤
 */
@implementation ViewController

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{

    [self download];
}
// 下载文件
- (void)download{

    // 1、创建文件管理者
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    
    // 确定URL
    NSURL *url = [NSURL URLWithString:@""];
    
    // 创建请求对象
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    // 下载文件
    /*
     * 第一个参数:请求对象
     * 第二个参数:progress 进度回调
     * 第三个参数:destination 回调(目标位置)
                有返回值
                targetPath:临时文件路径
                response:响应头信息
     * 第三个参数:completionHandler 下载完成之后的回调
                filePath:最终的文件路径 
                error :错误信息
     */
    NSURLSessionDownloadTask * task = [manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
        
        NSLog(@"%f",1.0 * downloadProgress.completedUnitCount / downloadProgress.totalUnitCount);
        
    } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
        
        NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];
        NSLog(@"%@",fullPath);
        return [NSURL fileURLWithPath:fullPath];
        
        
    } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
        
        NSLog(@"%@",filePath);
    }];
    
    [task resume];
}
// 上传文件
- (void)upload{

    // 创建会话管理者
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    
    // 发送请求上传文件 然后就依据NSURLSession类似的方式上传
    [manager uploadTaskWithRequest:nil fromData:nil progress:^(NSProgress * _Nonnull uploadProgress) {
        
    } completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
        
    }];
}
// 利用POST的方式上传文件
- (void)upload2{

    // 创建会话管理者
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    
    // 发送post请求上传文件
    /*
     第一个参数:请求路径
     第二个参数:字典(非文件参数) 可以不传
     第三个参数:constructingBodyWithBlock 处理要上传的文件数据
     第四个参数:进度回调
     第五个参数:成功回调 responseObject:响应体信息
     第六个参数:失败回调
     */
    [manager POST:@"" parameters:nil constructingBodyWithBlock:^(id  _Nonnull formData) {
        
        //使用formData来拼接数据
        /*
         第一个参数:二进制数据 要上传的文件参数
         第二个参数:服务器规定的
         第三个参数:该文件上传到服务器以什么名称保存
         */
        //[formData appendPartWithFileData:imageData name:@"file" fileName:@"xxxx.png" mimeType:@"image/png"];
        
        //[formData appendPartWithFileURL:[NSURL fileURLWithPath:@"/Users/xiaomage/Desktop/Snip.png"] name:@"file" fileName:@"123.png" mimeType:@"image/png" error:nil];
        
        [formData appendPartWithFileURL:[NSURL fileURLWithPath:@"/Users/xiaomage/Desktop/Snip.png"] name:@"file" error:nil];
        
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        
    }];
}

2、请求类封装

#import 
#import "AFNetworking.h"

@interface YYHttpTool : NSObject
/**
 *  发送一个GET请求
 *
 *  @param url     请求路径
 *  @param params  请求参数
 *  @param success 请求成功后的回调(请将请求成功后想做的事情写到这个block中)
 *  @param failure 请求失败后的回调(请将请求失败后想做的事情写到这个block中)
 */
+ (void)get:(NSString *)url params:(NSDictionary *)params success:(void(^)(id responseObj))success failure:(void(^)(NSError *error))failure;

/**
 *  发送一个POST请求
 *
 *  @param url     请求路径
 *  @param params  请求参数
 *  @param success 请求成功后的回调(请将请求成功后想做的事情写到这个block中)
 *  @param failure 请求失败后的回调(请将请求失败后想做的事情写到这个block中)
 */
+ (NSURLSessionDataTask *)post:(NSString *)url params:(NSDictionary *)params success:(void(^)(id responseObj))success failure:(void(^)(NSError *error))failure;
@end


#import "YYHttpTool.h"


@implementation YYHttpTool
+(void)get:(NSString *)url params:(NSDictionary *)params success:(void (^)(id))success failure:(void (^)(NSError *))failure
{
    //1.获得请求管理者
    AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager];
    
    //2.发送Get请求
    [mgr GET:url parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        if (success) {
            success(responseObject);
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        if (failure) {
            failure(error);
        }
    }];
}

+(NSURLSessionDataTask *)post:(NSString *)url params:(NSDictionary *)params success:(void (^)(id))success failure:(void (^)(NSError *))failure
{
    //1.获得请求管理者
    AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager];
    
   NSURLSessionDataTask *dataTask = [mgr POST:url parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
       
       if (success) {
           success(responseObject);
       }
       
   } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
       
       if (failure) {
           failure(error);
       }
   }];
    
    return dataTask;
}
@end

3、NSMutableURLRequest+XMGUpload 分类 上传的时候会使用 具体参照《iOS网络请求策略——NSURLSession的基本使用》中上传操作

#import 

@interface NSMutableURLRequest (XMGUpload)

/**
 *  生成单文件上传的 multipart/form-data 请求
 *
 *  @param URL     上传地址
 *  @param fileURL 要上传的本地文件地址
 *  @param name    服务器参数名称
 *
 *  @return multipart/form-data POST 请求,保存到服务器的文件名与本地的文件名一致
 */
+ (instancetype)requestWithURL:(NSURL *)URL fileURL:(NSURL *)fileURL name:(NSString *)name;

/**
 *  生成单文件上传的 multipart/form-data 请求
 *
 *  @param URL      上传地址
 *  @param fileURL  要上传的本地文件地址
 *  @param fileName 要保存在服务器上的文件名
 *  @param name     服务器参数名称
 *
 *  @return multipart/form-data POST 请求
 */
+ (instancetype)requestWithURL:(NSURL *)URL fileURL:(NSURL *)fileURL fileName:(NSString *)fileName name:(NSString *)name;

/**
 *  生成多文件上传的 multipart/form-data 请求
 *
 *  @param URL      上传地址
 *  @param fileURLs 要上传的本地文件地址 数组
 *  @param name     服务器参数名称
 *
 *  @return multipart/form-data POST 请求,保存到服务器的文件名与本地的文件名一致
 */
+ (instancetype)requestWithURL:(NSURL *)URL fileURLs:(NSArray *)fileURLs name:(NSString *)name;

/**
 *  生成多文件上传的 multipart/form-data 请求
 *
 *  @param URL       上传地址
 *  @param fileURLs  要上传的本地文件地址 数组
 *  @param fileNames 要保存在服务器上的文件名 数组
 *  @param name      服务器参数名称
 *
 *  @return multipart/form-data POST 请求
 */
+ (instancetype)requestWithURL:(NSURL *)URL fileURLs:(NSArray *)fileURLs fileNames:(NSArray *)fileNames name:(NSString *)name;


@end


#import "NSMutableURLRequest+XMGUpload.h"

@implementation NSMutableURLRequest (XMGUpload)

+ (instancetype)requestWithURL:(NSURL *)URL fileURL:(NSURL *)fileURL name:(NSString *)name {
    return [self requestWithURL:URL fileURLs:@[fileURL] name:name];
}

+ (instancetype)requestWithURL:(NSURL *)URL fileURL:(NSURL *)fileURL fileName:(NSString *)fileName name:(NSString *)name {
    return [self requestWithURL:URL fileURLs:@[fileURL] fileNames:@[fileName] name:name];
}

+ (instancetype)requestWithURL:(NSURL *)URL fileURLs:(NSArray *)fileURLs name:(NSString *)name {
    
    NSMutableArray *fileNames = [NSMutableArray arrayWithCapacity:fileURLs.count];
    [fileURLs enumerateObjectsUsingBlock:^(NSURL *fileURL, NSUInteger idx, BOOL *stop) {
        [fileNames addObject:fileURL.path.lastPathComponent];
    }];
    
    return [self requestWithURL:URL fileURLs:fileURLs fileNames:fileNames name:name];
}

+ (instancetype)requestWithURL:(NSURL *)URL fileURLs:(NSArray *)fileURLs fileNames:(NSArray *)fileNames name:(NSString *)name {
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
    
    request.HTTPMethod = @"POST";
    
    NSMutableData *data = [NSMutableData data];
    NSString *boundary = multipartFormBoundary();
    
    if (fileURLs.count > 1) {
        name = [name stringByAppendingString:@"[]"];
    }
    
    [fileURLs enumerateObjectsUsingBlock:^(NSURL *fileURL, NSUInteger idx, BOOL *stop) {
        NSString *bodyStr = [NSString stringWithFormat:@"\n--%@\n", boundary];
        [data appendData:[bodyStr dataUsingEncoding:NSUTF8StringEncoding]];
        
        NSString *fileName = fileNames[idx];
        bodyStr = [NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\" \n", name, fileName];
        [data appendData:[bodyStr dataUsingEncoding:NSUTF8StringEncoding]];
        [data appendData:[@"Content-Type: application/octet-stream\n\n" dataUsingEncoding:NSUTF8StringEncoding]];
        
        [data appendData:[NSData dataWithContentsOfURL:fileURL]];
        
        [data appendData:[@"\n" dataUsingEncoding:NSUTF8StringEncoding]];
    }];
    
    NSString *tailStr = [NSString stringWithFormat:@"--%@--\n", boundary];
    [data appendData:[tailStr dataUsingEncoding:NSUTF8StringEncoding]];
    
    request.HTTPBody = data;
    
    NSString *headerString = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
    [request setValue:headerString forHTTPHeaderField:@"Content-Type"];
    
    return request;
}

static NSString * multipartFormBoundary() {
    return [NSString stringWithFormat:@"Boundary+%08X%08X", arc4random(), arc4random()];
}
@end

二、XML解析(GET请求为例)

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    
    [self get];
}

- (void)get{
    // 创建会话管理者
    
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    // 返回的是xml的数据,修改AFN的解析方案
    manager.responseSerializer = [AFXMLParserResponseSerializer serializer];
    // 如果返回的数据既不是xml也不是json那么应该修改解析方案 比如图片
//    manager.responseSerializer = [AFHTTPResponseSerializer serializer];
    // 如果请求的是网站(html)
    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/html", nil];
    NSDictionary *params = @{
                             @"type":@"XML"
                             };
    
    // 发送get请求和发送post请求的方式相同,AFN把请求路径和参数进行了分离
    [manager GET:@"" parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
        // NSLog(@"%@",responseObject);
        
        // 创建解析器
        
        NSXMLParser *parser = (NSXMLParser *)responseObject;
        
        // 设置代理
        parser.delegate = self;
        
        // 开始解析
        [parser parse];
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        
        if (error) {
            
            NSLog(@"error--%@",error);
            
        }
        
    }];
}

- (void)parser:(NSXMLParser *)parser didStartElement:(nonnull NSString *)elementName namespaceURI:(nullable NSString *)namespaceURI qualifiedName:(nullable NSString *)qName attributes:(nonnull NSDictionary *)attributeDict{

    NSLog(@"%@--%@",elementName,attributeDict);
}


三、网络状态监测

// 检测网络状态

- (void)kvoStatus{

    // 获得一个网络状态管理者
    AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager manager];
    
    // 监听网络状态改变
    [manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
        /*
         AFNetworkReachabilityStatusUnknown          = -1,未知
         AFNetworkReachabilityStatusNotReachable     = 0,没有网络
         AFNetworkReachabilityStatusReachableViaWWAN = 1,蜂窝网络
         AFNetworkReachabilityStatusReachableViaWiFi = 2,wifi

         */
        switch (status) {
            case AFNetworkReachabilityStatusUnknown:
                NSLog(@"AFNetworkReachabilityStatusUnknown");
                break;
            case AFNetworkReachabilityStatusNotReachable:
                NSLog(@"AFNetworkReachabilityStatusNotReachable");
                break;
            case AFNetworkReachabilityStatusReachableViaWWAN:
                NSLog(@"AFNetworkReachabilityStatusReachableViaWWAN");
                break;
            case AFNetworkReachabilityStatusReachableViaWiFi:
                NSLog(@"AFNetworkReachabilityStatusReachableViaWiFi");
                break;
            default:
                break;
        }
        
    }];
    
    // 开始监听
    [manager stopMonitoring];
}

四、https请求的处理(GET请求为例)

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{

    [self get];
}

- (void)get{
  // 创建会话管理者
    
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    // 对于解析方式修改 https请求
    manager.responseSerializer = [AFHTTPResponseSerializer serializer];
    // 设置证书的处理方式 接收无效的证书
    manager.securityPolicy.allowInvalidCertificates = YES;
    // 设置对域名验证为无效
    manager.securityPolicy.validatesDomainName = NO;
    
    NSDictionary *params = @{
                          @"username":@"123",
                          @"pwd":@"123",
                          @"type":@"JSON"
                          };
    
    // 发送get请求和发送post请求的方式相同,AFN把请求路径和参数进行了分离
    [manager GET:@"" parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
        NSLog(@"%@",responseObject);
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        
    }];
}

五、https简介

/**
 * https简单说明
 HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。
 即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。 它是一个URI scheme(抽象标识符体系),句法类同http:体系。用于安全的HTTP数据传输。
 https:URL表明它使用了HTTP,但HTTPS存在不同于HTTP的默认端口及一个加密/身份验证层(在HTTP与TCP之间)。
 
 2.HTTPS和HTTP的区别主要为以下四点:
 一、https协议需要到ca申请证书,一般免费证书很少,需要交费。
 二、http是超文本传输协议,信息是明文传输,https 则是具有安全性的ssl加密传输协议。
 三、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
 四、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
 
 3.简单说明
 1)HTTPS的主要思想是在不安全的网络上创建一安全信道,并可在使用适当的加密包和服务器证书可被验证且可被信任时,对窃听和中间人攻击提供合理的保护。
 2)HTTPS的信任继承基于预先安装在浏览器中的证书颁发机构(如VeriSign、Microsoft等)(意即“我信任证书颁发机构告诉我应该信任的”)。
 3)因此,一个到某网站的HTTPS连接可被信任,如果服务器搭建自己的https 也就是说采用自认证的方式来建立https信道,这样一般在客户端是不被信任的。
 4)所以我们一般在浏览器访问一些https站点的时候会有一个提示,问你是否继续。
 */
- (void)https{

    // 确定URL
    NSURL *url = [NSURL URLWithString:@""];
    
    // 创建请求对象
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    // 创建会话对象
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    // 创建任务
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
    }];
    // 开启任务
    [task resume];
}
// 对于大型的网站并不会去质询,因为证书是强制安装的,数据可以直接拿到
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler{

    
    if (![challenge.protectionSpace.authenticationMethod isEqualToString:@"NSURLAuthenticationMethodServerTrust"]) {
        
        return;
    }
    NSLog(@"%@",challenge.protectionSpace);
    /*
     NSURLSessionAuthChallengeDisposition 如何处理证书
     NSURLSessionAuthChallengeUseCredential = 0,  使用该证书 安装证书                                     
    NSURLSessionAuthChallengePerformDefaultHandling = 1,默认采用方式 忽略
    NSURLSessionAuthChallengeCancelAuthenticationChallenge = 2, 证书被忽略 请求被取消
    NSURLSessionAuthChallengeRejectProtectionSpace = 3, 拒绝安装
     */
    
    // 创建身份信息
    NSURLCredential *credential = [[NSURLCredential alloc] initWithTrust:challenge.protectionSpace.serverTrust];
    
    completionHandler(NSURLSessionAuthChallengeUseCredential,credential);

   }


写在最后的话:关于AFNetworking的使用今天就分享到这里,关于AFNetworking使用方面的问题欢迎大家和我交流,共同进步,谢谢各位。

你可能感兴趣的:(iOS网络请求策略——AFNetworking的基本使用)