今天和大家一起來學(xué)習(xí)一下AFNetworking的基本使用,有疏忽的地方,還望各位不吝賜教。
一、AFNetworking的基本使用
1、控制器代碼
#import "ViewController.h"
#import <AFNetworking.h>
@interface ViewController ()
@end
/*
* 在開發(fā)中進行二次封裝可以簡化步驟
*/
@implementation ViewController
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self download];
}
// 下載文件
- (void)download{
// 1、創(chuàng)建文件管理者
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
// 確定URL
NSURL *url = [NSURL URLWithString:@""];
// 創(chuàng)建請求對象
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 下載文件
/*
* 第一個參數(shù):請求對象
* 第二個參數(shù):progress 進度回調(diào)
* 第三個參數(shù):destination 回調(diào)(目標(biāo)位置)
有返回值
targetPath:臨時文件路徑
response:響應(yīng)頭信息
* 第三個參數(shù):completionHandler 下載完成之后的回調(diào)
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{
// 創(chuàng)建會話管理者
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
// 發(fā)送請求上傳文件 然后就依據(jù)NSURLSession類似的方式上傳
[manager uploadTaskWithRequest:nil fromData:nil progress:^(NSProgress * _Nonnull uploadProgress) {
} completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {
}];
}
// 利用POST的方式上傳文件
- (void)upload2{
// 創(chuàng)建會話管理者
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
// 發(fā)送post請求上傳文件
/*
第一個參數(shù):請求路徑
第二個參數(shù):字典(非文件參數(shù)) 可以不傳
第三個參數(shù):constructingBodyWithBlock 處理要上傳的文件數(shù)據(jù)
第四個參數(shù):進度回調(diào)
第五個參數(shù):成功回調(diào) responseObject:響應(yīng)體信息
第六個參數(shù):失敗回調(diào)
*/
[manager POST:@"" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) {
//使用formData來拼接數(shù)據(jù)
/*
第一個參數(shù):二進制數(shù)據(jù) 要上傳的文件參數(shù)
第二個參數(shù):服務(wù)器規(guī)定的
第三個參數(shù):該文件上傳到服務(wù)器以什么名稱保存
*/
//[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 <Foundation/Foundation.h>
#import "AFNetworking.h"
@interface YYHttpTool : NSObject
/**
* 發(fā)送一個GET請求
*
* @param url 請求路徑
* @param params 請求參數(shù)
* @param success 請求成功后的回調(diào)(請將請求成功后想做的事情寫到這個block中)
* @param failure 請求失敗后的回調(diào)(請將請求失敗后想做的事情寫到這個block中)
*/
+ (void)get:(NSString *)url params:(NSDictionary *)params success:(void(^)(id responseObj))success failure:(void(^)(NSError *error))failure;
/**
* 發(fā)送一個POST請求
*
* @param url 請求路徑
* @param params 請求參數(shù)
* @param success 請求成功后的回調(diào)(請將請求成功后想做的事情寫到這個block中)
* @param failure 請求失敗后的回調(diào)(請將請求失敗后想做的事情寫到這個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.發(fā)送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網(wǎng)絡(luò)請求策略——NSURLSession的基本使用》中上傳操作
#import <Foundation/Foundation.h>
@interface NSMutableURLRequest (XMGUpload)
/**
* 生成單文件上傳的 multipart/form-data 請求
*
* @param URL 上傳地址
* @param fileURL 要上傳的本地文件地址
* @param name 服務(wù)器參數(shù)名稱
*
* @return multipart/form-data POST 請求,保存到服務(wù)器的文件名與本地的文件名一致
*/
+ (instancetype)requestWithURL:(NSURL *)URL fileURL:(NSURL *)fileURL name:(NSString *)name;
/**
* 生成單文件上傳的 multipart/form-data 請求
*
* @param URL 上傳地址
* @param fileURL 要上傳的本地文件地址
* @param fileName 要保存在服務(wù)器上的文件名
* @param name 服務(wù)器參數(shù)名稱
*
* @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 要上傳的本地文件地址 數(shù)組
* @param name 服務(wù)器參數(shù)名稱
*
* @return multipart/form-data POST 請求,保存到服務(wù)器的文件名與本地的文件名一致
*/
+ (instancetype)requestWithURL:(NSURL *)URL fileURLs:(NSArray *)fileURLs name:(NSString *)name;
/**
* 生成多文件上傳的 multipart/form-data 請求
*
* @param URL 上傳地址
* @param fileURLs 要上傳的本地文件地址 數(shù)組
* @param fileNames 要保存在服務(wù)器上的文件名 數(shù)組
* @param name 服務(wù)器參數(shù)名稱
*
* @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<UITouch *> *)touches withEvent:(UIEvent *)event{
[self get];
}
- (void)get{
// 創(chuàng)建會話管理者
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
// 返回的是xml的數(shù)據(jù),修改AFN的解析方案
manager.responseSerializer = [AFXMLParserResponseSerializer serializer];
// 如果返回的數(shù)據(jù)既不是xml也不是json那么應(yīng)該修改解析方案 比如圖片
// manager.responseSerializer = [AFHTTPResponseSerializer serializer];
// 如果請求的是網(wǎng)站(html)
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/html", nil];
NSDictionary *params = @{
@"type":@"XML"
};
// 發(fā)送get請求和發(fā)送post請求的方式相同,AFN把請求路徑和參數(shù)進行了分離
[manager GET:@"" parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
// NSLog(@"%@",responseObject);
// 創(chuàng)建解析器
NSXMLParser *parser = (NSXMLParser *)responseObject;
// 設(shè)置代理
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<NSString *,NSString *> *)attributeDict{
NSLog(@"%@--%@",elementName,attributeDict);
}
三、網(wǎng)絡(luò)狀態(tài)監(jiān)測
// 檢測網(wǎng)絡(luò)狀態(tài)
- (void)kvoStatus{
// 獲得一個網(wǎng)絡(luò)狀態(tài)管理者
AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager manager];
// 監(jiān)聽網(wǎng)絡(luò)狀態(tài)改變
[manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
/*
AFNetworkReachabilityStatusUnknown = -1,未知
AFNetworkReachabilityStatusNotReachable = 0,沒有網(wǎng)絡(luò)
AFNetworkReachabilityStatusReachableViaWWAN = 1,蜂窩網(wǎng)絡(luò)
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;
}
}];
// 開始監(jiān)聽
[manager stopMonitoring];
}
四、https請求的處理(GET請求為例)
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self get];
}
- (void)get{
// 創(chuàng)建會話管理者
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
// 對于解析方式修改 https請求
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
// 設(shè)置證書的處理方式 接收無效的證書
manager.securityPolicy.allowInvalidCertificates = YES;
// 設(shè)置對域名驗證為無效
manager.securityPolicy.validatesDomainName = NO;
NSDictionary *params = @{
@"username":@"123",
@"pwd":@"123",
@"type":@"JSON"
};
// 發(fā)送get請求和發(fā)送post請求的方式相同,AFN把請求路徑和參數(shù)進行了分離
[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),是以安全為目標(biāo)的HTTP通道,簡單講是HTTP的安全版。
即HTTP下加入SSL層,HTTPS的安全基礎(chǔ)是SSL,因此加密的詳細(xì)內(nèi)容就需要SSL。 它是一個URI scheme(抽象標(biāo)識符體系),句法類同http:體系。用于安全的HTTP數(shù)據(jù)傳輸。
https:URL表明它使用了HTTP,但HTTPS存在不同于HTTP的默認(rèn)端口及一個加密/身份驗證層(在HTTP與TCP之間)。
2.HTTPS和HTTP的區(qū)別主要為以下四點:
一、https協(xié)議需要到ca申請證書,一般免費證書很少,需要交費。
二、http是超文本傳輸協(xié)議,信息是明文傳輸,https 則是具有安全性的ssl加密傳輸協(xié)議。
三、http和https使用的是完全不同的連接方式,用的端口也不一樣,前者是80,后者是443。
四、http的連接很簡單,是無狀態(tài)的;HTTPS協(xié)議是由SSL+HTTP協(xié)議構(gòu)建的可進行加密傳輸、身份認(rèn)證的網(wǎng)絡(luò)協(xié)議,比http協(xié)議安全。
3.簡單說明
1)HTTPS的主要思想是在不安全的網(wǎng)絡(luò)上創(chuàng)建一安全信道,并可在使用適當(dāng)?shù)募用馨头?wù)器證書可被驗證且可被信任時,對竊聽和中間人攻擊提供合理的保護。
2)HTTPS的信任繼承基于預(yù)先安裝在瀏覽器中的證書頒發(fā)機構(gòu)(如VeriSign、Microsoft等)(意即“我信任證書頒發(fā)機構(gòu)告訴我應(yīng)該信任的”)。
3)因此,一個到某網(wǎng)站的HTTPS連接可被信任,如果服務(wù)器搭建自己的https 也就是說采用自認(rèn)證的方式來建立https信道,這樣一般在客戶端是不被信任的。
4)所以我們一般在瀏覽器訪問一些https站點的時候會有一個提示,問你是否繼續(xù)。
*/
- (void)https{
// 確定URL
NSURL *url = [NSURL URLWithString:@""];
// 創(chuàng)建請求對象
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 創(chuàng)建會話對象
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
// 創(chuàng)建任務(wù)
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
}];
// 開啟任務(wù)
[task resume];
}
// 對于大型的網(wǎng)站并不會去質(zhì)詢,因為證書是強制安裝的,數(shù)據(jù)可以直接拿到
- (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,默認(rèn)采用方式 忽略
NSURLSessionAuthChallengeCancelAuthenticationChallenge = 2, 證書被忽略 請求被取消
NSURLSessionAuthChallengeRejectProtectionSpace = 3, 拒絕安裝
*/
// 創(chuàng)建身份信息
NSURLCredential *credential = [[NSURLCredential alloc] initWithTrust:challenge.protectionSpace.serverTrust];
completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
}