(四)iOS 網絡編程之HTTP、HTTPS、NSURLConnection 和 NSURLSession

在移動互聯網時代,幾乎所有的應用都用到網絡請求,只有通過網絡和外界進行數據交互、數據更新,應用才能保持新鮮和活力。網絡編程也是 iOS 面試中常問到的問題。下面整理一下 iOS 開發中涉及到的網絡編程知識:HTTP、HTTPS、NSURLConnection 和 NSURLSession


(一)HTTP 協議和 HTTPS 協議

HTTP協議

HTTP(Hypertext Transfer Protocol)協議是超文本傳輸協議,是互聯網上應用最為廣泛的一種網絡協議。簡單來說,HTTP 是客戶端和服務器端之間請求和應答的標準。

HTTP 協議工作過程

分為4個步驟:

  1. 客戶端與服務器需要建立連接。例如,單擊某個超鏈接,瀏覽器和服務器將建立通信連接。
  2. 建立連接后,客戶端發送一個請求給服務器,請求方式的格式為:統一資源標識符(URL)、協議版本號,后邊是MIME信息包括請求修飾符、客戶端信息和可能的內容。
  3. 服務器接收到請求后,給予相應的響應信息,其格式為一個狀態行,包括信息的協議版本號、一個成功或錯誤的代碼,后面是 MIME 信息包括服務器信息、實體信息和可能的內容。
  4. 客戶端接收服務器所返回的信息通過瀏覽器顯示在用戶的顯示屏上,然后客戶機與服務器斷開連接。
HTTPS協議

HTTPS(Secure Hypertext Transfer Protocol)安全超文本傳輸協議它是一個安全通信通道,它基于HTTP開發,用于在客戶計算機和服務器之間交換信息。它使用安全套接字層(SSL)進行信息交換,簡單來說它是HTTP的安全版。

HTTPS和HTTP的區別:

1、https協議需要到ca申請證書,一般免費證書很少,需要交費。
2、http是超文本傳輸協議,信息是明文傳輸,https 則是具有安全性的ssl加密傳輸協議。
3、http和https使用的是完全不同的連接方式,用的端口也不一樣,前者是80,后者是443。
4、http的連接很簡單,是無狀態的。
5、HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議要比http協議安全。

App Transport Security(簡稱ATS)特性

iOS9中新增App Transport Security(簡稱ATS)特性, 讓原來請求時候用到的HTTP,全部都轉向TLS1.2協議進行傳輸,這意味著所有的HTTP協議都強制使用了HTTPS協議進行傳輸。如果我們在iOS9下直接進行HTTP請求是會報錯,系統會告訴我們不能直接使用HTTP進行請求,需要在Info.plist中控制ATS的配置。


(二)NSURLConnection 和 NSURLSession 進行網絡請求

NSURLConnection

NSURLConnection 是 iOS 開發中最經典的網絡請求方案。雖然在蘋果公司推出 NSURLSession 后已經不推薦使用 NSURLConnection 了(NSURLConnection 在 iOS 9 被宣布棄用了),但是在一些早先構建的項目和框架中可能任使用了 NSURLConnection 技術,所以還是有必要了解 NSURLConnection。

NSURLConnection 使用步驟
  1. 創建一個 NSURL 對象,用于設置請求路徑。
  2. 創建一個 NSURLRequest 對象,并設置請求頭、請求體等請求參數。
  3. 創建一個 NSURLResponse 對象用于接收響應數據,一般用 NSURLResponse 的子類 NSHPPTURLResponse。
  4. 使用 NSURLConnection 發送同步或異步請求。
  5. 可以使用 NSURLConnectionDelegate 監聽網絡請求的響應。
    具體實現可參考網址 NSURLConnection
NSURLSession

在 iOS 9.0 之后,以前使用的 NSURLConnection 被棄用,蘋果推薦使用 NSURLSession 來替換NSURLConnection 完成網路請求相關操作。

NSURLSession 使用步驟

NSURLSession 的使用非常簡單,先根據會話對象創建一個請求Task,然后執行該Task即可。
NSURLSessionTask 本身是一個抽象類,在使用的時候,通常是根據具體的需求使用它的幾個子類。關系如下:


NSURLSessionTask.png

下面關于 NSURLSession 的 GET 和 POST 的使用直接摘錄于 iOS開發網絡篇—發送GET和POST請求(使用NSURLSession) 。非常感謝。

NSURLSession GET 請求方法

1)確定請求路徑(一般由公司的后臺開發人員以接口文檔的方式提供),GET請求參數直接跟在URL后面。
2)創建請求對象(默認包含了請求頭和請求方法【GET】),此步驟可以省略。
3)創建會話對象(NSURLSession)。
4)根據會話對象創建請求任務(NSURLSessionDataTask)。
5)執行請求 Task。
6)當得到服務器返回的響應后,解析數據(XML 或者 JSON)。
代碼如下:
第一種方法:

-(void)getByNSURLSession1
{
    //對請求路徑的說明
    //http://120.25.226.186:32812/login?username=520it&pwd=520&type=JSON
    //協議頭+主機地址+接口名稱+?+參數1&參數2&參數3
    //協議頭(http://)+主機地址(120.25.226.186:32812)+接口名稱(login)+?+參數1(username=520it)&參數2(pwd=520)&參數3(type=JSON)
    //GET請求,直接把請求參數跟在URL的后面以?隔開,多個參數之間以&符號拼接
    
    //1.確定請求路徑
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520it&pwd=520it&type=JSON"];
    
    //2.創建請求對象
    //請求對象內部默認已經包含了請求頭和請求方法(GET)
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    //3.獲得會話對象
    NSURLSession *session = [NSURLSession sharedSession];
      
    //4.根據會話對象創建一個Task(發送請求)
    /*
     第一個參數:請求對象
     第二個參數:completionHandler回調(請求完成【成功|失敗】的回調)
               data:響應體信息(期望的數據)
               response:響應頭信息,主要是對服務器端的描述
               error:錯誤信息,如果請求失敗,則error有值
     */
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        if (error == nil) {
            //6.解析服務器返回的數據
            //說明:(此處返回的數據是JSON格式的,因此使用NSJSONSerialization進行反序列化處理)
            NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
            
            NSLog(@"%@",dict);
        }
    }];
    
    //5.執行任務
    [dataTask resume];
}

//這是 NSURLSession 發送GET請求的第一種方法

第二種方法:

-(void)getByNSURLSession2
{
    //1.確定請求路徑
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520it&pwd=520it&type=JSON"];
    
    //2.獲得會話對象
    NSURLSession *session = [NSURLSession sharedSession];
    
    //3.根據會話對象創建一個Task(發送請求)
    /*
     第一個參數:請求路徑
     第二個參數:completionHandler回調(請求完成【成功|失敗】的回調)
               data:響應體信息(期望的數據)
               response:響應頭信息,主要是對服務器端的描述
               error:錯誤信息,如果請求失敗,則error有值
     注意:
        1)該方法內部會自動將請求路徑包裝成一個請求對象,該請求對象默認包含了請求頭信息和請求方法(GET)
        2)如果要發送的是POST請求,則不能使用該方法
     */
    NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        //5.解析數據
        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
        NSLog(@"%@",dict);
        
    }];
    
    //4.執行任務
    [dataTask resume];
}

//這是 NSURLSession 發送GET請求的第二種方法
NSURLSession POST請求方法

1)確定請求路徑(一般由公司的后臺開發人員以接口文檔的方式提供)。
2)創建可變的請求對象(因為需要修改),此步驟不可以省略。
3)修改請求方法為POST。
4)設置請求體,把參數轉換為二進制數據并設置請求體。
5)創建會話對象(NSURLSession)。
6)根據會話對象創建請求任務(NSURLSessionDataTask)。
7)執行任務 Task。
8)當得到服務器返回的響應后,解析數據(XML 或者 JSON)。

代碼如下:

-(void)postByNSURLSession
{
    //對請求路徑的說明
    //http://120.25.226.186:32812/login
    //協議頭+主機地址+接口名稱
    //協議頭(http://)+主機地址(120.25.226.186:32812)+接口名稱(login)
    //POST請求需要修改請求方法為POST,并把參數轉換為二進制數據設置為請求體
    
    //1.創建會話對象
    NSURLSession *session = [NSURLSession sharedSession];
    
    //2.根據會話對象創建task
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login"];
    
    //3.創建可變的請求對象
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    
    //4.修改請求方法為POST
    request.HTTPMethod = @"POST";
    
    //5.設置請求體
    request.HTTPBody = [@"username=520it&pwd=520it&type=JSON" dataUsingEncoding:NSUTF8StringEncoding];
    
    //6.根據會話對象創建一個Task(發送請求)
    /*
     第一個參數:請求對象
     第二個參數:completionHandler回調(請求完成【成功|失敗】的回調)
                data:響應體信息(期望的數據)
                response:響應頭信息,主要是對服務器端的描述
                error:錯誤信息,如果請求失敗,則error有值
     */
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        //8.解析數據
        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
        NSLog(@"%@",dict);
        
    }];
    
    //7.執行任務
    [dataTask resume];
}

// 發送POST請求的方法
NSURLSession 代理方法

有的時候,我們可能需要監聽網絡請求的過程(如下載文件需監聽文件下載進度),那么就需要用到代理方法。
接下來通過代碼簡單說明NSURLSession中普通網絡請求會涉及代理方法的使用。

#import "ViewController.h"

@interface ViewController ()<NSURLSessionDataDelegate>
@property (nonatomic, strong) NSMutableData *responseData;
@end

@implementation ViewController

-(NSMutableData *)responseData
{
    if (_responseData == nil) {
        _responseData = [NSMutableData data];
    }
    return _responseData;
}

//當點擊控制器View的時候會調用該方法
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self delegateTest];
}

//發送請求,代理方法
-(void)delegateTest
{
    //1.確定請求路徑
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520it&pwd=520it&type=JSON"];
    
    //2.創建請求對象
    //請求對象內部默認已經包含了請求頭和請求方法(GET)
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    //3.獲得會話對象,并設置代理
    /*
     第一個參數:會話對象的配置信息defaultSessionConfiguration 表示默認配置
     第二個參數:誰成為代理,此處為控制器本身即self
     第三個參數:隊列,該隊列決定代理方法在哪個線程中調用,可以傳主隊列|非主隊列
     [NSOperationQueue mainQueue]   主隊列:   代理方法在主線程中調用
     [[NSOperationQueue alloc]init] 非主隊列: 代理方法在子線程中調用
     */
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    
    //4.根據會話對象創建一個Task(發送請求)
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];
    
    //5.執行任務
    [dataTask resume];
}

//1.接收到服務器響應的時候調用該方法
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
{
    //在該方法中可以得到響應頭信息,即response
    NSLog(@"didReceiveResponse--%@",[NSThread currentThread]);
    
    //注意:需要使用completionHandler回調告訴系統應該如何處理服務器返回的數據
    //默認是取消的
    /*
        NSURLSessionResponseCancel = 0,        默認的處理方式,取消
        NSURLSessionResponseAllow = 1,         接收服務器返回的數據
        NSURLSessionResponseBecomeDownload = 2,變成一個下載請求
        NSURLSessionResponseBecomeStream        變成一個流
     */
    
    completionHandler(NSURLSessionResponseAllow);
}

//2.接收到服務器返回數據的時候會調用該方法,如果數據較大那么該方法可能會調用多次
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
{
    NSLog(@"didReceiveData--%@",[NSThread currentThread]);
    
    //拼接服務器返回的數據
    [self.responseData appendData:data];
}

//3.當請求完成(成功|失敗)的時候會調用該方法,如果請求失敗,則error有值
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
    NSLog(@"didCompleteWithError--%@",[NSThread currentThread]);
    
    if(error == nil)
    {
        //解析數據,JSON解析請參考http://www.cnblogs.com/wendingding/p/3815303.html
        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:self.responseData options:kNilOptions error:nil];
        NSLog(@"%@",dict);
    }
}
@end
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,488評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,034評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,327評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,554評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,337評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,883評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,975評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,114評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,625評論 1 332
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,555評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,737評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,244評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,973評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,615評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,343評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,699評論 2 370

推薦閱讀更多精彩內容