網(wǎng)絡(luò)在開發(fā)中無處不在,網(wǎng)絡(luò)方面的知識又比較雜,下面分享一下關(guān)于網(wǎng)絡(luò)的一些基礎(chǔ)知識,幫助大家快速了解一些知識.鞏固基礎(chǔ),做到舉一反三,日進(jìn)漸進(jìn).
如果你已經(jīng)掌握了基礎(chǔ)內(nèi)容,可以閱讀我的另一篇文章《關(guān)于AFNetworking桦锄,初級程序員到高級工程師的修煉之路》
1 網(wǎng)絡(luò)基礎(chǔ)
1)問題:為什么要學(xué)習(xí)網(wǎng)絡(luò)編程扎附?
(1)網(wǎng)絡(luò)編程是一種實(shí)時更新應(yīng)用數(shù)據(jù)的常用手段
(2)網(wǎng)絡(luò)編程是開發(fā)優(yōu)秀網(wǎng)絡(luò)應(yīng)用的前提和基礎(chǔ)
2)網(wǎng)絡(luò)基本概念
(1)客戶端(就是手機(jī)或者ipad等手持設(shè)備上面的APP)
(2)服務(wù)器(遠(yuǎn)程服務(wù)器-本地服務(wù)器)
(3)請求(客戶端索要數(shù)據(jù)的方式)
(4)響應(yīng)(需要客戶端解析數(shù)據(jù))
(5)數(shù)據(jù)庫(服務(wù)器的數(shù)據(jù)從哪里來)
2 Http
1)URL
(1)如何找到服務(wù)器(通過一個唯一的URL)
(2)URL介紹
a. 統(tǒng)一資源定位符
b. url格式(協(xié)議\主機(jī)地址\路徑)
協(xié)議:不同的協(xié)議,代表著不同的資源查找方式察纯、資源傳輸方式
主機(jī)地址:存放資源的主機(jī)(服務(wù)器)的IP地址(域名)
路徑:資源在主機(jī)(服務(wù)器)中的具體位置
(3)請求協(xié)議
【file】訪問的是本地計(jì)算機(jī)上的資源帕棉,格式是file://(不用加主機(jī)地址)
【ftp】訪問的是共享主機(jī)的文件資源,格式是ftp://
【mailto】訪問的是電子郵件地址饼记,格式是mailto:
【http】超文本傳輸協(xié)議香伴,訪問的是遠(yuǎn)程的網(wǎng)絡(luò)資源,格式是http://(網(wǎng)絡(luò)請求中最常用的協(xié)議)
2)http協(xié)議
(1)http協(xié)議簡單介紹
a.超文本傳輸協(xié)議
b.規(guī)定客戶端和服務(wù)器之間的數(shù)據(jù)傳輸格式
c.讓客戶端和服務(wù)器能有效地進(jìn)行數(shù)據(jù)溝通
(2)http協(xié)議優(yōu)缺點(diǎn)
a.簡單快速(協(xié)議簡單具则,服務(wù)器端程序規(guī)模小即纲,通信速度快)
b.靈活(允許傳輸各種數(shù)據(jù))
c.非持續(xù)性連接(1.1之前版本是非持續(xù)的,即限制每次連接只處理一個請求博肋,服務(wù)器對客戶端的請求做出響應(yīng)后低斋,馬上斷開連接,這種方式可以節(jié)省傳輸時間)
(3)基本通信過程
a.請求:客戶端向服務(wù)器索要數(shù)據(jù)
b.響應(yīng):服務(wù)器返回客戶端相應(yīng)的數(shù)據(jù)
3) GET和POST請求
(1)http里面發(fā)送請求的方法
GET(常用)匪凡、POST(常用)膊畴、OPTIONS、HEAD病游、PUT唇跨、DELETE、TRACE衬衬、CONNECT买猖、PATCH
(2)GET和POST請求的對比【區(qū)別在于參數(shù)如何傳遞】
GET
在請求URL后面以?的形式跟上發(fā)給服務(wù)器的參數(shù),多個參數(shù)之間用&隔開滋尉,比如
http://ww.GF.com/login?username=GF&pwd=GF&type=JSON
由于瀏覽器和服務(wù)器對URL長度有限制玉控,因此在URL后面附帶的參數(shù)是有限制的,通常不能超過1KB
POST
發(fā)給服務(wù)器的參數(shù)全部放在請求體中
理論上狮惜,POST傳遞的數(shù)據(jù)量沒有限制(具體還得看服務(wù)器的處理能力)
(3)如何選擇【除簡單數(shù)據(jù)查詢外高诺,其它的一律使用POST請求】
a.如果要傳遞大量數(shù)據(jù),比如文件上傳碾篡,只能用POST請求
b.GET的安全性比POST要差些懒叛,如果包含機(jī)密\敏感信息,建議用POST
c.如果僅僅是索取數(shù)據(jù)(數(shù)據(jù)查詢)耽梅,建議使用GET
d.如果是增加、修改胖烛、刪除數(shù)據(jù)眼姐,建議使用POST
4)iOS中發(fā)送http請求的方案
(1)蘋果原生
NSURLConnection 03年推出的古老技術(shù)
NSURLSession 13年推出iOS7之后诅迷,以取代NSURLConnection【重點(diǎn)】
CFNetwork 底層技術(shù)、C語言的
(2)第三方框架
ASIHttpRequest
AFNetworking 【重點(diǎn)】
MKNetworkKit
5)http請求通信過程
(1)請求
【包括請求頭+請求體·非必選】
(2)響應(yīng)
【響應(yīng)頭+響應(yīng)體】
(3)通信過程
a.發(fā)送請求的時候把請求頭和請求體(請求體是非必須的)包裝成一個請求對象
b.服務(wù)器端對請求進(jìn)行響應(yīng)众旗,在響應(yīng)信息中包含響應(yīng)頭和響應(yīng)體罢杉,響應(yīng)信息是對服務(wù)器端的描述,具體的信息放在響應(yīng)體中傳遞給客戶端
(4)狀態(tài)碼
【200】:請求成功
【400】:客戶端請求的語法錯誤贡歧,服務(wù)器無法解析
【404】:無法找到資源
【500】:服務(wù)器內(nèi)部錯誤滩租,無法完成請求
2 NSURLConnection的基本使用
1 NSURLConnection同步請求(GET)
1)發(fā)送網(wǎng)絡(luò)請求的步驟
(1)設(shè)置請求路徑
(2)創(chuàng)建請求對象(默認(rèn)是GET請求,且已經(jīng)默認(rèn)包含了請求頭)
(3)使用NSURLSession sendsync方法發(fā)送網(wǎng)絡(luò)請求
(4)接收到服務(wù)器的響應(yīng)后利朵,解析響應(yīng)體
2)相關(guān)代碼
//1.確定請求路徑
NSURL *url = [NSURL URLWithString:@"http://114.114.114.114:32812/login?username=GF&pwd=GF&type=XML"];
//NSURL *url = [NSURL URLWithString:@"http://114.114.114.114:32812/video?type=XML"];
//2.創(chuàng)建一個請求對象
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//3.把請求發(fā)送給服務(wù)器
//sendSynchronousRequest 阻塞式的方法律想,會卡住線程
NSHTTPURLResponse *response = nil;
NSError *error = nil;
/*
第一個參數(shù):請求對象
第二個參數(shù):響應(yīng)頭信息,當(dāng)該方法執(zhí)行完畢之后绍弟,該參數(shù)被賦值
第三個參數(shù):錯誤信息技即,如果請求失敗,則error有值
*/
//該方法是阻塞式的樟遣,會卡住線程
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
//4.解析服務(wù)器返回的數(shù)據(jù)
NSString *str = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
2 NSURLConnection異步請求(GET-SendAsync)
1)相關(guān)說明
01 該方法不會卡住當(dāng)前線程而叼,網(wǎng)絡(luò)請求任務(wù)是異步執(zhí)行的
2)相關(guān)代碼
//1.確定請求路徑
NSURL *url = [NSURL URLWithString:@"http://114.114.114.114:32812/login?username=GF&pwd=GF"];
//2.創(chuàng)建一個請求對象
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//3.把請求發(fā)送給服務(wù)器,發(fā)送一個異步請求
/*
第一個參數(shù):請求對象
第二個參數(shù):回調(diào)方法在哪個線程中執(zhí)行,如果是主隊(duì)列則block在主線程中執(zhí)行豹悬,非主隊(duì)列則在子線程中執(zhí)行
第三個參數(shù):completionHandlerBlock塊:接受到響應(yīng)的時候執(zhí)行該block中的代碼
response:響應(yīng)頭信息
data:響應(yīng)體
connectionError:錯誤信息葵陵,如果請求失敗,那么該參數(shù)有值
*/
[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc]init] completionHandler:^(NSURLResponse * __nullable response, NSData * __nullable data, NSError * __nullable connectionError) {
//4.解析服務(wù)器返回的數(shù)據(jù)
NSString *str = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
//轉(zhuǎn)換并打印響應(yīng)頭信息
NSHTTPURLResponse *r = (NSHTTPURLResponse *)response;
NSLog(@"--%zd---%@--",r.statusCode,r.allHeaderFields);
}];
3 NSURLConnection異步請求(GET-代理)
1)步驟
(1)確定請求路徑
(2)創(chuàng)建請求對象
(3)創(chuàng)建NSURLConnection對象并設(shè)置代理
(4)遵守NSURLConnectionDataDelegate協(xié)議瞻佛,并實(shí)現(xiàn)相應(yīng)的代理方法
(5)在代理方法中監(jiān)聽網(wǎng)絡(luò)請求的響應(yīng)
2)設(shè)置代理的幾種方法
/*
設(shè)置代理的第一種方式:自動發(fā)送網(wǎng)絡(luò)請求
[[NSURLConnection alloc]initWithRequest:request delegate:self];
*/
/*
設(shè)置代理的第二種方式:
第一個參數(shù):請求對象
第二個參數(shù):誰成為NSURLConnetion對象的代理
第三個參數(shù):是否馬上發(fā)送網(wǎng)絡(luò)請求脱篙,如果該值為YES則立刻發(fā)送,如果為NO則不會發(fā)送網(wǎng)路請求
NSURLConnection *conn = [[NSURLConnection alloc]initWithRequest:request delegate:self startImmediately:NO];
//調(diào)用該方法控制網(wǎng)絡(luò)請求的發(fā)送
[conn start];
*/
//設(shè)置代理的第三種方式:使用類方法設(shè)置代理涤久,會自動發(fā)送網(wǎng)絡(luò)請求
NSURLConnection *conn = [NSURLConnection connectionWithRequest:request delegate:self];
//取消網(wǎng)絡(luò)請求
//[conn cancel];
3)相關(guān)的代理方法
/*
1.當(dāng)接收到服務(wù)器響應(yīng)的時候調(diào)用
第一個參數(shù)connection:監(jiān)聽的是哪個NSURLConnection對象
第二個參數(shù)response:接收到的服務(wù)器返回的響應(yīng)頭信息
*/
- (void)connection:(nonnull NSURLConnection *)connection didReceiveResponse:(nonnull NSURLResponse *)response
/*
2.當(dāng)接收到數(shù)據(jù)的時候調(diào)用涡尘,該方法會被調(diào)用多次
第一個參數(shù)connection:監(jiān)聽的是哪個NSURLConnection對象
第二個參數(shù)data:本次接收到的服務(wù)端返回的二進(jìn)制數(shù)據(jù)(可能是片段)
*/
- (void)connection:(nonnull NSURLConnection *)connection didReceiveData:(nonnull NSData *)data
/*
3.當(dāng)服務(wù)端返回的數(shù)據(jù)接收完畢之后會調(diào)用
通常在該方法中解析服務(wù)器返回的數(shù)據(jù)
*/
-(void)connectionDidFinishLoading:(nonnull NSURLConnection *)connection
/*4.當(dāng)請求錯誤的時候調(diào)用(比如請求超時)
第一個參數(shù)connection:NSURLConnection對象
第二個參數(shù):網(wǎng)絡(luò)請求的錯誤信息,如果請求失敗响迂,則error有值
*/
- (void)connection:(nonnull NSURLConnection *)connection didFailWithError:(nonnull NSError *)error
4)其它知識點(diǎn)
01 關(guān)于消息彈窗第三方框架的使用
SVProgressHUD
02 字符串截取相關(guān)方法
- (NSRange)rangeOfString:(NSString *)searchString;
- (NSString *)substringWithRange:(NSRange)range;
4 NSURLConnection發(fā)送POST請求
1)發(fā)送POST請求步驟
a.確定URL路徑
b.創(chuàng)建請求對象(可變對象)
c.修改請求對象的方法為POST考抄,設(shè)置請求體(Data)
d.發(fā)送一個異步請求
e.補(bǔ)充:設(shè)置請求超時,處理錯誤信息蔗彤,設(shè)置請求頭(如獲取客戶端的版本等等,請求頭是可設(shè)置可不設(shè)置的)
2)相關(guān)代碼
//1.確定請求路徑
NSURL *url = [NSURL URLWithString:@"http://114.114.114.114:32812/login"];
//2.創(chuàng)建請求對象
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//2.1更改請求方法
request.HTTPMethod = @"POST";
//2.2設(shè)置請求體
request.HTTPBody = [@"username=GF&pwd=GF" dataUsingEncoding:NSUTF8StringEncoding];
//2.3請求超時
request.timeoutInterval = 5;
//2.4設(shè)置請求頭
[request setValue:@"iOS9.0" forHTTPHeaderField:@"User-Agent"];
//3.發(fā)送請求
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * __nullable response, NSData * __nullable data, NSError * __nullable connectionError) {
//4.解析服務(wù)器返回的數(shù)據(jù)
if (connectionError) {
NSLog(@"--請求失敗-");
}else
{
NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
}
}];
5 URL中文轉(zhuǎn)碼問題
//1.確定請求路徑
NSString *urlStr = @"http://114.114.114.114:32812/login2?username=GF&pwd=GF";
NSLog(@"%@",urlStr);
//中文轉(zhuǎn)碼操作
urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(@"%@",urlStr);
NSURL *url = [NSURL URLWithString:urlStr];
3 NSURLConnection和Runloop(面試)
1 兩種為NSURLConnection設(shè)置代理方式的區(qū)別
//第一種設(shè)置方式:
//通過該方法設(shè)置代理川梅,會自動的發(fā)送請求
// [[NSURLConnection alloc]initWithRequest:request delegate:self];
//第二種設(shè)置方式:
//設(shè)置代理,startImmediately為NO的時候然遏,該方法不會自動發(fā)送請求
NSURLConnection *connect = [[NSURLConnection alloc]initWithRequest:request delegate:self startImmediately:NO];
//手動通過代碼的方式來發(fā)送請求
//注意該方法內(nèi)部會自動的把connect添加到當(dāng)前線程的RunLoop中在默認(rèn)模式下執(zhí)行
[connect start];
2 如何控制代理方法在哪個線程調(diào)用
//說明:默認(rèn)情況下贫途,代理方法會在主線程中進(jìn)行調(diào)用(為了方便開發(fā)者拿到數(shù)據(jù)后處理一些刷新UI的操作不需要考慮到線程間通信)
//設(shè)置代理方法的執(zhí)行隊(duì)列
[connect setDelegateQueue:[[NSOperationQueue alloc]init]];
3 開子線程發(fā)送網(wǎng)絡(luò)請求的注意點(diǎn),適用于自動發(fā)送網(wǎng)絡(luò)請求模式
//在子線程中發(fā)送網(wǎng)絡(luò)請求-調(diào)用startf方法發(fā)送
-(void)createNewThreadSendConnect1
{
//1.創(chuàng)建一個非主隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//2.封裝操作待侵,并把任務(wù)添加到隊(duì)列中執(zhí)行
[queue addOperationWithBlock:^{
NSLog(@"%@",[NSThread currentThread]);
//2-1.確定請求路徑
NSURL *url = [NSURL URLWithString:@"http://114.114.114.114:32812/login?username=dd&pwd=ww&type=JSON"];
//2-2.創(chuàng)建請求對象
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//2-3.使用NSURLConnection設(shè)置代理丢早,發(fā)送網(wǎng)絡(luò)請求
NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:request delegate:self startImmediately:YES];
//2-4.設(shè)置代理方法在哪個隊(duì)列中執(zhí)行,如果是非主隊(duì)列,那么代理方法將再子線程中執(zhí)行
[connection setDelegateQueue:[[NSOperationQueue alloc]init]];
//2-5.發(fā)送網(wǎng)絡(luò)請求
//注意:start方法內(nèi)部會把當(dāng)前的connect對象作為一個source添加到當(dāng)前線程對應(yīng)的runloop中
//區(qū)別在于怨酝,如果調(diào)用start方法開發(fā)送網(wǎng)絡(luò)請求傀缩,那么再添加source的過程中,如果當(dāng)前runloop不存在
//那么該方法內(nèi)部會自動創(chuàng)建一個當(dāng)前線程對應(yīng)的runloop,并啟動农猬。
[connection start];
}];
}
//在子線程中發(fā)送網(wǎng)絡(luò)請求-自動發(fā)送網(wǎng)絡(luò)請求
-(void)createNewThreadSendConnect2
{
NSLog(@"-----");
//1.創(chuàng)建一個非主隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//2.封裝操作赡艰,并把任務(wù)添加到隊(duì)列中執(zhí)行
[queue addOperationWithBlock:^{
//2-1.確定請求路徑
NSURL *url = [NSURL URLWithString:@"http://114.114.114.114:32812/login?username=GF&pwd=GF&type=JSON"];
//2-2.創(chuàng)建請求對象
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//2-3.使用NSURLConnection設(shè)置代理,發(fā)送網(wǎng)絡(luò)請求
//注意:該方法內(nèi)部雖然會把connection添加到runloop,但是如果當(dāng)前的runloop不存在斤葱,那么不會主動創(chuàng)建慷垮。
NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
//2-4.設(shè)置代理方法在哪個隊(duì)列中執(zhí)行,如果是非主隊(duì)列揍堕,那么代理方法將再子線程中執(zhí)行
[connection setDelegateQueue:[[NSOperationQueue alloc]init]];
//2-5 創(chuàng)建當(dāng)前線程對應(yīng)的runloop,并開啟
[[NSRunLoop currentRunLoop]run];
}];
}
4 NSURLSession的基本使用
1 NSURLSession的基本使用
1)使用步驟
使用NSURLSession創(chuàng)建task,然后執(zhí)行task
2)關(guān)于task
a.NSURLSessionTask是一個抽象類料身,本身不能使用,只能使用它的子類
b.NSURLSessionDataTask\NSURLSessionUploadTask\NSURLSessionDownloadTask
3)發(fā)送get請求
//1.創(chuàng)建NSURLSession對象(可以獲取單例對象)
NSURLSession *session = [NSURLSession sharedSession];
//2.根據(jù)NSURLSession對象創(chuàng)建一個Task
NSURL *url = [NSURL URLWithString:@"http://114.114.114.114:32812/login?username=GF&pwd=GF&type=JSON"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//方法參數(shù)說明
/*
注意:該block是在子線程中調(diào)用的鹤啡,如果拿到數(shù)據(jù)之后要做一些UI刷新操作惯驼,那么需要回到主線程刷新
第一個參數(shù):需要發(fā)送的請求對象
block:當(dāng)請求結(jié)束拿到服務(wù)器響應(yīng)的數(shù)據(jù)時調(diào)用block
block-NSData:該請求的響應(yīng)體
block-NSURLResponse:存放本次請求的響應(yīng)信息,響應(yīng)頭递瑰,真實(shí)類型為NSHTTPURLResponse
block-NSErroe:請求錯誤信息
*/
NSURLSessionDataTask * dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * __nullable data, NSURLResponse * __nullable response, NSError * __nullable error) {
//拿到響應(yīng)頭信息
NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;
//4.解析拿到的響應(yīng)數(shù)據(jù)
NSLog(@"%@\n%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding],res.allHeaderFields);
}];
//3.執(zhí)行Task
//注意:剛創(chuàng)建出來的task默認(rèn)是掛起狀態(tài)的祟牲,需要調(diào)用該方法來啟動任務(wù)(執(zhí)行任務(wù))
[dataTask resume];
4)發(fā)送get請求的第二種方式
//注意:該方法內(nèi)部默認(rèn)會把URL對象包裝成一個NSURLRequest對象(默認(rèn)是GET請求)
//方法參數(shù)說明
/*
//第一個參數(shù):發(fā)送請求的URL地址
//block:當(dāng)請求結(jié)束拿到服務(wù)器響應(yīng)的數(shù)據(jù)時調(diào)用block
//block-NSData:該請求的響應(yīng)體
//block-NSURLResponse:存放本次請求的響應(yīng)信息,響應(yīng)頭抖部,真實(shí)類型為NSHTTPURLResponse
//block-NSErroe:請求錯誤信息
*/
- (nullable NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url completionHandler:(void (^)(NSData * __nullable data, NSURLResponse * __nullable response, NSError * __nullable error))completionHandler;
5)發(fā)送POST請求
//1.創(chuàng)建NSURLSession對象(可以獲取單例對象)
NSURLSession *session = [NSURLSession sharedSession];
//2.根據(jù)NSURLSession對象創(chuàng)建一個Task
NSURL *url = [NSURL URLWithString:@"http://114.114.114.114:32812/login"];
//創(chuàng)建一個請求對象说贝,并這是請求方法為POST,把參數(shù)放在請求體中傳遞
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
request.HTTPBody = [@"username=520it&pwd=520it&type=JSON" dataUsingEncoding:NSUTF8StringEncoding];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * __nullable data, NSURLResponse * __nullable response, NSError * __nullable error) {
//拿到響應(yīng)頭信息
NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;
//解析拿到的響應(yīng)數(shù)據(jù)
NSLog(@"%@\n%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding],res.allHeaderFields);
}];
//3.執(zhí)行Task
//注意:剛創(chuàng)建出來的task默認(rèn)是掛起狀態(tài)的慎颗,需要調(diào)用該方法來啟動任務(wù)(執(zhí)行任務(wù))
[dataTask resume];