(四)iOS 網(wǎng)絡(luò)編程之HTTP事秀、HTTPS彤断、NSURLConnection 和 NSURLSession

在移動互聯(lián)網(wǎng)時代,幾乎所有的應(yīng)用都用到網(wǎng)絡(luò)請求易迹,只有通過網(wǎng)絡(luò)和外界進(jìn)行數(shù)據(jù)交互宰衙、數(shù)據(jù)更新,應(yīng)用才能保持新鮮和活力睹欲。網(wǎng)絡(luò)編程也是 iOS 面試中常問到的問題供炼。下面整理一下 iOS 開發(fā)中涉及到的網(wǎng)絡(luò)編程知識:HTTP、HTTPS窘疮、NSURLConnection 和 NSURLSession


(一)HTTP 協(xié)議和 HTTPS 協(xié)議

HTTP協(xié)議

HTTP(Hypertext Transfer Protocol)協(xié)議是超文本傳輸協(xié)議袋哼,是互聯(lián)網(wǎng)上應(yīng)用最為廣泛的一種網(wǎng)絡(luò)協(xié)議。簡單來說闸衫,HTTP 是客戶端和服務(wù)器端之間請求和應(yīng)答的標(biāo)準(zhǔn)涛贯。

HTTP 協(xié)議工作過程

分為4個步驟:

  1. 客戶端與服務(wù)器需要建立連接。例如蔚出,單擊某個超鏈接弟翘,瀏覽器和服務(wù)器將建立通信連接。
  2. 建立連接后骄酗,客戶端發(fā)送一個請求給服務(wù)器稀余,請求方式的格式為:統(tǒng)一資源標(biāo)識符(URL)、協(xié)議版本號酥筝,后邊是MIME信息包括請求修飾符滚躯、客戶端信息和可能的內(nèi)容。
  3. 服務(wù)器接收到請求后,給予相應(yīng)的響應(yīng)信息掸掏,其格式為一個狀態(tài)行茁影,包括信息的協(xié)議版本號、一個成功或錯誤的代碼丧凤,后面是 MIME 信息包括服務(wù)器信息募闲、實(shí)體信息和可能的內(nèi)容。
  4. 客戶端接收服務(wù)器所返回的信息通過瀏覽器顯示在用戶的顯示屏上愿待,然后客戶機(jī)與服務(wù)器斷開連接浩螺。
HTTPS協(xié)議

HTTPS(Secure Hypertext Transfer Protocol)安全超文本傳輸協(xié)議它是一個安全通信通道,它基于HTTP開發(fā)仍侥,用于在客戶計算機(jī)和服務(wù)器之間交換信息要出。它使用安全套接字層(SSL)進(jìn)行信息交換,簡單來說它是HTTP的安全版农渊。

HTTPS和HTTP的區(qū)別:

1患蹂、https協(xié)議需要到ca申請證書,一般免費(fèi)證書很少砸紊,需要交費(fèi)传于。
2、http是超文本傳輸協(xié)議醉顽,信息是明文傳輸沼溜,https 則是具有安全性的ssl加密傳輸協(xié)議。
3游添、http和https使用的是完全不同的連接方式,用的端口也不一樣,前者是80,后者是443系草。
4、http的連接很簡單,是無狀態(tài)的否淤。
5悄但、HTTPS協(xié)議是由SSL+HTTP協(xié)議構(gòu)建的可進(jìn)行加密傳輸、身份認(rèn)證的網(wǎng)絡(luò)協(xié)議要比http協(xié)議安全石抡。

App Transport Security(簡稱ATS)特性

iOS9中新增App Transport Security(簡稱ATS)特性, 讓原來請求時候用到的HTTP,全部都轉(zhuǎn)向TLS1.2協(xié)議進(jìn)行傳輸助泽,這意味著所有的HTTP協(xié)議都強(qiáng)制使用了HTTPS協(xié)議進(jìn)行傳輸啰扛。如果我們在iOS9下直接進(jìn)行HTTP請求是會報錯,系統(tǒng)會告訴我們不能直接使用HTTP進(jìn)行請求嗡贺,需要在Info.plist中控制ATS的配置隐解。


(二)NSURLConnection 和 NSURLSession 進(jìn)行網(wǎng)絡(luò)請求

NSURLConnection

NSURLConnection 是 iOS 開發(fā)中最經(jīng)典的網(wǎng)絡(luò)請求方案。雖然在蘋果公司推出 NSURLSession 后已經(jīng)不推薦使用 NSURLConnection 了(NSURLConnection 在 iOS 9 被宣布棄用了)诫睬,但是在一些早先構(gòu)建的項(xiàng)目和框架中可能任使用了 NSURLConnection 技術(shù)煞茫,所以還是有必要了解 NSURLConnection。

NSURLConnection 使用步驟
  1. 創(chuàng)建一個 NSURL 對象,用于設(shè)置請求路徑续徽。
  2. 創(chuàng)建一個 NSURLRequest 對象蚓曼,并設(shè)置請求頭、請求體等請求參數(shù)钦扭。
  3. 創(chuàng)建一個 NSURLResponse 對象用于接收響應(yīng)數(shù)據(jù)纫版,一般用 NSURLResponse 的子類 NSHPPTURLResponse。
  4. 使用 NSURLConnection 發(fā)送同步或異步請求客情。
  5. 可以使用 NSURLConnectionDelegate 監(jiān)聽網(wǎng)絡(luò)請求的響應(yīng)。
    具體實(shí)現(xiàn)可參考網(wǎng)址 NSURLConnection
NSURLSession

在 iOS 9.0 之后,以前使用的 NSURLConnection 被棄用窑眯,蘋果推薦使用 NSURLSession 來替換NSURLConnection 完成網(wǎng)路請求相關(guān)操作获黔。

NSURLSession 使用步驟

NSURLSession 的使用非常簡單,先根據(jù)會話對象創(chuàng)建一個請求Task仰担,然后執(zhí)行該Task即可籽御。
NSURLSessionTask 本身是一個抽象類,在使用的時候惰匙,通常是根據(jù)具體的需求使用它的幾個子類技掏。關(guān)系如下:


NSURLSessionTask.png

下面關(guān)于 NSURLSession 的 GET 和 POST 的使用直接摘錄于 iOS開發(fā)網(wǎng)絡(luò)篇—發(fā)送GET和POST請求(使用NSURLSession) 。非常感謝项鬼。

NSURLSession GET 請求方法

1)確定請求路徑(一般由公司的后臺開發(fā)人員以接口文檔的方式提供)哑梳,GET請求參數(shù)直接跟在URL后面。
2)創(chuàng)建請求對象(默認(rèn)包含了請求頭和請求方法【GET】)绘盟,此步驟可以省略鸠真。
3)創(chuàng)建會話對象(NSURLSession)。
4)根據(jù)會話對象創(chuàng)建請求任務(wù)(NSURLSessionDataTask)龄毡。
5)執(zhí)行請求 Task吠卷。
6)當(dāng)?shù)玫椒?wù)器返回的響應(yīng)后,解析數(shù)據(jù)(XML 或者 JSON)沦零。
代碼如下:
第一種方法:

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

//這是 NSURLSession 發(fā)送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.根據(jù)會話對象創(chuàng)建一個Task(發(fā)送請求)
    /*
     第一個參數(shù):請求路徑
     第二個參數(shù):completionHandler回調(diào)(請求完成【成功|失敗】的回調(diào))
               data:響應(yīng)體信息(期望的數(shù)據(jù))
               response:響應(yīng)頭信息桩撮,主要是對服務(wù)器端的描述
               error:錯誤信息敦第,如果請求失敗,則error有值
     注意:
        1)該方法內(nèi)部會自動將請求路徑包裝成一個請求對象店量,該請求對象默認(rèn)包含了請求頭信息和請求方法(GET)
        2)如果要發(fā)送的是POST請求芜果,則不能使用該方法
     */
    NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        //5.解析數(shù)據(jù)
        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
        NSLog(@"%@",dict);
        
    }];
    
    //4.執(zhí)行任務(wù)
    [dataTask resume];
}

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

1)確定請求路徑(一般由公司的后臺開發(fā)人員以接口文檔的方式提供)。
2)創(chuàng)建可變的請求對象(因?yàn)樾枰薷模┑婀穑瞬襟E不可以省略师幕。
3)修改請求方法為POST。
4)設(shè)置請求體诬滩,把參數(shù)轉(zhuǎn)換為二進(jìn)制數(shù)據(jù)并設(shè)置請求體霹粥。
5)創(chuàng)建會話對象(NSURLSession)。
6)根據(jù)會話對象創(chuàng)建請求任務(wù)(NSURLSessionDataTask)疼鸟。
7)執(zhí)行任務(wù) Task后控。
8)當(dāng)?shù)玫椒?wù)器返回的響應(yīng)后,解析數(shù)據(jù)(XML 或者 JSON)空镜。

代碼如下:

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

// 發(fā)送POST請求的方法
NSURLSession 代理方法

有的時候,我們可能需要監(jiān)聽網(wǎng)絡(luò)請求的過程(如下載文件需監(jiān)聽文件下載進(jìn)度)洼怔,那么就需要用到代理方法署惯。
接下來通過代碼簡單說明NSURLSession中普通網(wǎng)絡(luò)請求會涉及代理方法的使用。

#import "ViewController.h"

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

@implementation ViewController

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

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

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

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

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

//3.當(dāng)請求完成(成功|失敗)的時候會調(diào)用該方法咙边,如果請求失敗,則error有值
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
    NSLog(@"didCompleteWithError--%@",[NSThread currentThread]);
    
    if(error == nil)
    {
        //解析數(shù)據(jù),JSON解析請參考http://www.cnblogs.com/wendingding/p/3815303.html
        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:self.responseData options:kNilOptions error:nil];
        NSLog(@"%@",dict);
    }
}
@end
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末琉雳,一起剝皮案震驚了整個濱河市样眠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌翠肘,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,865評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辫秧,死亡現(xiàn)場離奇詭異束倍,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評論 3 399
  • 文/潘曉璐 我一進(jìn)店門绪妹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來甥桂,“玉大人,你說我怎么就攤上這事邮旷』蒲。” “怎么了?”我有些...
    開封第一講書人閱讀 169,631評論 0 364
  • 文/不壞的土叔 我叫張陵婶肩,是天一觀的道長办陷。 經(jīng)常有香客問我,道長律歼,這世上最難降的妖魔是什么民镜? 我笑而不...
    開封第一講書人閱讀 60,199評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮险毁,結(jié)果婚禮上制圈,老公的妹妹穿的比我還像新娘。我一直安慰自己畔况,他們只是感情好鲸鹦,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,196評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著跷跪,像睡著了一般馋嗜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上域庇,一...
    開封第一講書人閱讀 52,793評論 1 314
  • 那天嵌戈,我揣著相機(jī)與錄音,去河邊找鬼听皿。 笑死熟呛,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的尉姨。 我是一名探鬼主播庵朝,決...
    沈念sama閱讀 41,221評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼又厉!你這毒婦竟也來了九府?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,174評論 0 277
  • 序言:老撾萬榮一對情侶失蹤覆致,失蹤者是張志新(化名)和其女友劉穎侄旬,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體煌妈,經(jīng)...
    沈念sama閱讀 46,699評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡儡羔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,770評論 3 343
  • 正文 我和宋清朗相戀三年宣羊,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片汰蜘。...
    茶點(diǎn)故事閱讀 40,918評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡仇冯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出族操,到底是詐尸還是另有隱情苛坚,我是刑警寧澤,帶...
    沈念sama閱讀 36,573評論 5 351
  • 正文 年R本政府宣布色难,位于F島的核電站泼舱,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏莱预。R本人自食惡果不足惜柠掂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,255評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望依沮。 院中可真熱鬧涯贞,春花似錦、人聲如沸危喉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,749評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽辜限。三九已至皇拣,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間薄嫡,已是汗流浹背氧急。 一陣腳步聲響...
    開封第一講書人閱讀 33,862評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留毫深,地道東北人吩坝。 一個月前我還...
    沈念sama閱讀 49,364評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像哑蔫,于是被迫代替她去往敵國和親钉寝。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,926評論 2 361

推薦閱讀更多精彩內(nèi)容