iOS開發網絡篇—使用AFN框架進行文件下載


1.AFN使用技巧

1.在開發的時候可以創建一個工具類,繼承自我們的AFN中的請求管理者,再控制器中真正發請求的代碼使用自己封裝的工具類。
2.這樣做的優點是以后如果修改了底層依賴的框架,那么我們修改這個工具類就可以了,而不用再一個一個的去修改。
3.該工具類一般提供一個單例方法,在該方法中會設置一個基本的請求路徑。
4.該方法通常還會提供對GET或POST請求的封裝。
5.在外面的時候通過該工具類來發送請求
6.單例方法:
+ (instancetype)shareNetworkTools
{
    static XMGNetworkTools *instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        // 注意: BaseURL中一定要以/結尾
        instance = [[self alloc] initWithBaseURL:[NSURL URLWithString:@"http://120.25.226.186:32812/"]];
    });
    return instance;
}

2.AFN文件上傳

1.文件上傳拼接數據的第一種方式
[formData appendPartWithFileData:data name:@"file" fileName:@"xxoo.png" mimeType:@"application/octet-stream"];
2.文件上傳拼接數據的第二種方式
 [formData appendPartWithFileURL:fileUrl name:@"file" fileName:@"xx.png" mimeType:@"application/octet-stream" error:nil];
3.文件上傳拼接數據的第三種方式
 [formData appendPartWithFileURL:fileUrl name:@"file" error:nil];
4.【注】在資料中已經提供了一個用於文件上傳的分類。

/*文件上傳相關的代碼如下*/
-(void)upload
{
    //1.創建一個請求管理者
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

    //2.發送POST請求上傳數據
    /*
     第一個參數:請求路徑:NSString類型
     第二個參數:要上傳的非文件參數
     第三個參數:block回調
        在該回調中,需要利用formData拼接即將上傳的二進制數據
     第三個參數:上傳成功的block回調
        task:dataTask(任務)
        responseObject:服務器返回的數據
     第四個參數:上傳失敗的block回調
        error:錯誤信息,如果上傳文件失敗,那么error里面包含了錯誤的描述信息
     */

    NSDictionary *dict = @{
                           @"username":@"wenidngding"
                           };

    [manager POST:@"http://120.25.226.186:32812/upload" parameters:dict constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {

        //把本地的圖片轉換為NSData類型的數據
        UIImage *image = [UIImage imageNamed:@"123"];
        NSData *data = UIImagePNGRepresentation(image);

        /*
         //拼接二進制文件數據
         第一個參數:要上傳的文件的二進制數據
         第二個參數:服務器接口規定的名稱
         第三個參數:這個參數上傳到服務器之后用什么名字來進行保存
         第四個參數:上傳文件的MIMEType類型
         */
        [formData appendPartWithFileData:data name:@"file" fileName:@"xxoo.png" mimeType:@"application/octet-stream"];

    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nonnull responseObject) {
        NSLog(@"請求成功---%@",responseObject);

    } failure:^(NSURLSessionDataTask * _Nonnull task, NSError * _Nonnull error) {
        NSLog(@"請求失敗--%@",error);
    }];
}

-(void)upload2
{
    NSLog(@"%s",__func__);

    //1.創建一個請求管理者
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

    //2.發送POST請求上傳數據
    /*
     第一個參數:請求路徑:NSString類型
     第二個參數:要上傳的非文件參數
     第三個參數:block回調
     在該回調中,需要利用formData拼接即將上傳的二進制數據
     第三個參數:上傳成功的block回調
     task:dataTask(任務)
     responseObject:服務器返回的數據
     第四個參數:上傳失敗的block回調
     error:錯誤信息,如果上傳文件失敗,那么error里面包含了錯誤的描述信息
     */

    NSDictionary *dict = @{
                           @"username":@"wenidngding"
                           };

    [manager POST:@"http://120.25.226.186:32812/upload" parameters:dict constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {

        //本地文件的url
        NSURL *fileUrl = [NSURL fileURLWithPath:@"/Users/文頂頂/Desktop/KF[WTI`AQ3T`A@3R(B96D89.gif"];
        /*
         //拼接二進制文件數據
         第一個參數:要上傳文件的url路徑
         第二個參數:服務器要求的參數名稱
         第三個參數:這個文件上傳到服務器之后叫什么名稱
         第四個參數:文件的mimetype類型
         第五個參數:錯誤信息
         */
//        [formData appendPartWithFileURL:fileUrl name:@"file" fileName:@"xx.png" mimeType:@"application/octet-stream" error:nil];

        //另外一種上傳文件的方式
        /*
         說明:該方法和上面的方法等價,不過該方法更加簡單其內部會自動的的根據url路徑確定文件保存名稱,並通過內部方法獲取上傳文件的mimetype類型
         */
        [formData appendPartWithFileURL:fileUrl name:@"file" error:nil];


    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nonnull responseObject) {
        NSLog(@"請求成功---%@",responseObject);

    } failure:^(NSURLSessionDataTask * _Nonnull task, NSError * _Nonnull error) {
        NSLog(@"請求失敗--%@",error);
    }];
}

3.使用AFN進行序列化處理

/*
1.AFN它內部默認把服務器響應的數據當做json來進行解析,所以如果服務器返回給我的不是JSON數據那么請求報錯,這個時候需要設置AFN對響應信息的解析方式。AFN提供了三種解析響應信息的方式,分別是:
1)AFXMLParserResponseSerializer----XML
2) AFHTTPResponseSerializer---------默認二進制響應數據
3)AFJSONResponseSerializer---------JSON

2.還有一種情況就是服務器返回給我們的數據格式不太一致(開發者工具Content-Type:text/xml),那么這種情況也有可能請求不成功。解決方法:
1) 直接在源代碼中修改,添加相應的Content-Type
2) 拿到這個屬性,添加到它的集合中

3.相關代碼
-(void)srializer
{
    //1.創建請求管理者,內部基於NSURLSession
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

    /* 知識點1:設置AFN采用什么樣的方式來解析服務器返回的數據*/

    //如果返回的是XML,那么告訴AFN,響應的時候使用XML的方式解析
    manager.responseSerializer = [AFXMLParserResponseSerializer serializer];

    //如果返回的就是二進制數據,那么采用默認二進制的方式來解析數據
    //manager.responseSerializer = [AFHTTPResponseSerializer serializer];

    //采用JSON的方式來解析數據
    //manager.responseSerializer = [AFJSONResponseSerializer serializer];


    /*知識點2: 告訴AFN服務器返回的數據內容是什么類型的 Content-Type*/
    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:@"text/xml"];

    //2.把所有的請求參數通過字典的方式來裝載,GET方法內部會自動把所有的鍵值對取出以&符號拼接並最后用?符號連接在請求路徑后面
    NSDictionary *dict = @{
                           @"username":@"223",
                           @"pwd":@"ewr",
                           @"type":@"XML"
                           };

    //3.發送GET請求
    [manager GET:@"http://120.25.226.186:32812/login" parameters:dict success:^(NSURLSessionDataTask * _Nonnull task, id  _Nonnull responseObject) {

        //4.請求成功的回調block
        NSLog(@"%@",[responseObject class]);
    } failure:^(NSURLSessionDataTask * _Nonnull task, NSError * _Nonnull error) {

        //5.請求失敗的回調,可以打印error的值查看錯誤信息
        NSLog(@"%@",error);
    }];
}

4.使用AFN來檢測網絡狀態

/*
說明:可以使用AFN框架中的AFNetworkReachabilityManager來監聽網絡狀態的改變,也可以利用蘋果提供的Reachability來監聽。建議在開發中直接使用AFN框架處理。
 */
//使用AFN框架來檢測網絡狀態的改變
-(void)AFNReachability
{
    //1.創建網絡監聽管理者
    AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager sharedManager];

    //2.監聽網絡狀態的改變
    /*
     AFNetworkReachabilityStatusUnknown          = 未知
     AFNetworkReachabilityStatusNotReachable     = 沒有網絡
     AFNetworkReachabilityStatusReachableViaWWAN = 3G
     AFNetworkReachabilityStatusReachableViaWiFi = WIFI
     */
    [manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
        switch (status) {
            case AFNetworkReachabilityStatusUnknown:
                NSLog(@"未知");
                break;
            case AFNetworkReachabilityStatusNotReachable:
                NSLog(@"沒有網絡");
                break;
            case AFNetworkReachabilityStatusReachableViaWWAN:
                NSLog(@"3G");
                break;
            case AFNetworkReachabilityStatusReachableViaWiFi:
                NSLog(@"WIFI");
                break;

            default:
                break;
        }
    }];

    //3.開始監聽
    [manager startMonitoring];
}

------------------------------------------------------------
//使用蘋果提供的Reachability來檢測網絡狀態,如果要持續監聽網絡狀態的概念,需要結合通知一起使用。
//提供下載地址:https://developer.apple.com/library/ios/samplecode/Reachability/Reachability.zip

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    //1.注冊一個通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkChange) name:kReachabilityChangedNotification object:nil];

    //2.拿到一個對象,然后調用開始監聽方法
    Reachability *r = [Reachability reachabilityForInternetConnection];
    [r startNotifier];

    //持有該對象,不要讓該對象釋放掉
    self.r = r;
}

//當控制器釋放的時候,移除通知的監聽
-(void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

-(void)networkChange
{
    //獲取當前網絡的狀態
    if([Reachability reachabilityForLocalWiFi].currentReachabilityStatus != NotReachable)
    {
        NSLog(@"當前網絡為WIFI");
    }else if ([Reachability reachabilityForInternetConnection].currentReachabilityStatus != NotReachable)
    {
        NSLog(@"當前網絡為手機自帶網絡");
    }else
    {
        NSLog(@"當前沒有網絡");
    }
}

5.數據安全

01 攻城利器:Charles(公司中一般都使用該工具來抓包,並做網絡測試)
注意:Charles在使用中的亂碼問題,可以顯示包內容,然后打開info.plist文件,找到java目錄下面的VMOptions,在后面添加一項:-Dfile.encoding=UTF-8
02 MD5消息摘要算法是不可逆的。
03 數據加密的方式和規范一般公司會有具體的規定,不必多花時間。

6.HTTPS的基本使用

1.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.對開發的影響。
3.1 如果是自己使用NSURLSession來封裝網絡請求,涉及代碼如下。
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];

    NSURLSessionDataTask *task =  [session dataTaskWithURL:[NSURL URLWithString:@"https://www.apple.com"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
    }];
    [task resume];
}

/*
 只要請求的地址是HTTPS的, 就會調用這個代理方法
 我們需要在該方法中告訴系統, 是否信任服務器返回的證書
 Challenge: 挑戰 質問 (包含了受保護的區域)
 protectionSpace : 受保護區域
 NSURLAuthenticationMethodServerTrust : 證書的類型是 服務器信任
 了解:證書有好幾種,一種是被認證過的一種是沒有被認證過的,如果證書是被認證過的,那么只需要信任一次就可以了,如果是沒有被認證過的,那么每次都需要重新認證
 */
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler
{
    //    NSLog(@"didReceiveChallenge %@", challenge.protectionSpace);
    NSLog(@"調用了最外層");
    // 1.判斷服務器返回的證書類型, 是否是服務器信任
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        NSLog(@"調用了里面這一層是服務器信任的證書");
        /*
         NSURLSessionAuthChallengeUseCredential = 0,                     使用證書
         NSURLSessionAuthChallengePerformDefaultHandling = 1,            忽略證書(默認的處理方式)
         NSURLSessionAuthChallengeCancelAuthenticationChallenge = 2,     忽略書證, 並取消這次請求
         NSURLSessionAuthChallengeRejectProtectionSpace = 3,            忽略當前這一次, 下一次再詢問
         */
//        NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];

        NSURLCredential *card = [[NSURLCredential alloc]initWithTrust:challenge.protectionSpace.serverTrust];

        completionHandler(NSURLSessionAuthChallengeUseCredential , card);
    }
}

3.2 如果是使用AFN框架,那么我們不需要做任何額外的操作,AFN內部已經做了處理。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM