網路編程 網路編程是一種實時更新應用數據的常用手段 網路編程是開發優秀網路應用的前提和基礎 網路基本概念 客戶端(就是手機或者ipad等手持設備上面的APP) 伺服器(遠程伺服器 本地伺服器) 請求(客戶端索要數據的方式) 響應(需要客戶端解析數據) 資料庫(伺服器的數據從哪裡來) HTTP URL ...
- 網路編程
- 網路編程是一種實時更新應用數據的常用手段
網路編程是開發優秀網路應用的前提和基礎
- 網路基本概念
- 客戶端(就是手機或者ipad等手持設備上面的APP)
- 伺服器(遠程伺服器-本地伺服器)
- 請求(客戶端索要數據的方式)
- 響應(需要客戶端解析數據)
資料庫(伺服器的數據從哪裡來)
HTTP
URL
- 如何找到伺服器(通過一個唯一的URL)
- URL介紹
- 統一資源定位符
- url格式(協議\主機地址\路徑)
- 協議:不同的協議,代表著不同的資源查找方式、資源傳輸方式
- 主機地址:存放資源的主機(伺服器)的IP地址(功能變數名稱)
- 路徑:資源在主機(伺服器)中的具體位置
- 請求協議
- 【file】訪問的是本地電腦上的資源,格式是file://(不用加主機地址)
- 【ftp】訪問的是共用主機的文件資源,格式是ftp://
- 【mailto】訪問的是電子郵件地址,格式是mailto:
- 【http】超文本傳輸協議,訪問的是遠程的網路資源,格式是http://(網路請求中最常用的協議)
HTTP協議
- 簡介
- a.超文本傳輸協議
- b.規定客戶端和伺服器之間的數據傳輸格式
c.讓客戶端和伺服器能有效地進行數據溝通
- 優缺點
- a.簡單快速(協議簡單,伺服器端程式規模小,通信速度快)
- b.靈活(允許傳輸各種數據)
- c.非持續性連接(1.1之前版本是非持續的,即限制每次連接只處理一個請求,伺服器對客戶端的請求做出響應後,馬上斷開連接,這種方式可以節省傳輸時間)
- 基本通信過程
- a.請求:客戶端向伺服器索要數據
b.響應:伺服器返回客戶端相應的數據
GET和POST請求
- HTTP裡面發送請求的方法
GET(常用)、POST(常用)、OPTIONS、HEAD、PUT、DELETE、TRACE、CONNECT、PATCH
- GET和POST請求的對比【區別在於參數如何傳遞】
- GET
- 在請求URL後面以?的形式跟上發給伺服器的參數,多個參數之間用&隔開,比如
http://www.test.com/login?username=123&pwd=234&type=JSON - 由於瀏覽器和伺服器對URL長度有限制,因此在URL後面附帶的參數是有限制的,通常不能超過1KB
- 在請求URL後面以?的形式跟上發給伺服器的參數,多個參數之間用&隔開,比如
- POST
- 發給伺服器的參數全部放在請求體中
- 理論上,POST傳遞的數據量沒有限制(具體還得看伺服器的處理能力)
- 如何選擇【除簡單數據查詢外,其它的一律使用POST請求】
- a.如果要傳遞大量數據,比如文件上傳,只能用POST請求
- b.GET的安全性比POST要差些,如果包含機密\敏感信息,建議用POST
- c.如果僅僅是索取數據(數據查詢),建議使用GET
d.如果是增加、修改、刪除數據,建議使用POST
iOS中發送HTTP請求的方案
蘋果原生 | 特點 |
---|---|
NSURLConnection | 03年推出的古老技術 |
NSURLSession | 13年推出iOS7之後,以取代NSURLConnection 【重點】 |
CFNetwork | 底層技術、C語言的 |
常用第三方框架
第三方框架 | |
---|---|
ASIHttpRequest | |
AFNetworking | 開發常用 |
MKNetworkKit |
HTTP請求通信過程
- 請求
- 【包括請求頭+請求體·非必選】
- 響應
- 【響應頭+響應體】
- 通信過程
- a.發送請求的時候把請求頭和請求體(請求體是非必須的)包裝成一個請求對象
- b.伺服器端對請求進行響應,在響應信息中包含響應頭和響應體,響應信息是對伺服器端的描述,具體的信息放在響應體中傳遞給客戶端
- 狀態碼
- 【200】:請求成功
- 【400】:客戶端請求的語法錯誤,伺服器無法解析
- 【404】:無法找到資源
- 【500】:伺服器內部錯誤,無法完成請求
NSURLConnection使用
NSURLConnection同步請求(GET)
步驟
1 確定請求路徑
2 創建請求對象(預設是GET請求,且已經預設包含了請求頭)
3 使用NSURLSession sendsync方法發送網路請求
4 接收到伺服器的響應後,解析響應體
代碼
// 1.確定路徑
NSURL *url = [NSURL URLWithString:@"http://m.news.baidu.com/news?fr=mohome&ssid=0&from=1001703a&uid=&pu=sz%401320_1001%2Cta%40iphone_2_5.0_3_537&bd_page_type=1"];
// 2.創建請求對象
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 3.發送同步請求
NSURLResponse *response = nil;
NSError *error = nil;
// sendSynchronousRequest阻塞式的方法,會卡住線程
/*
第一個參數:請求對象
第二個參數:響應頭信息,當該方法執行完畢之後,該參數被賦值
第三個參數:錯誤信息,如果請求失敗,則error有值
*/
NSData *date = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
// 4.解析伺服器返回的數據
NSString *string = [[NSString alloc] initWithData:date encoding:NSUTF8StringEncoding];
NSURLConnection非同步請求(GET-SendAsync)
說明
該方法不會卡住當前線程,網路請求任務是非同步執行的
代碼
// 1.確定路徑
NSURL *url = [NSURL URLWithString:@"http://m.news.baidu.com/news?fr=mohome&ssid=0&from=1001703a&uid=&pu=sz%401320_1001%2Cta%40iphone_2_5.0_3_537&bd_page_type=1"];
// 2.創建請求對象
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 3.發送非同步請求
/*
第一個參數:請求對象
第二個參數:回調方法在哪個線程中執行,如果是主隊列則block在主線程中執行,非主隊列則在子線程中執行
第三個參數:completionHandlerBlock塊:接受到響應的時候執行該block中的代碼
response:響應頭信息
data:響應體
connectionError:錯誤信息,如果請求失敗,那麼該參數有值
*/
[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc]init] completionHandler:^(NSURLResponse * __nullable response, NSData * __nullable data, NSError * __nullable connectionError) {
// 4.解析伺服器返回的數據
NSString *str = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
// 轉換並列印響應頭信息
NSHTTPURLResponse *r = (NSHTTPURLResponse *)response;
NSLog(@"--%zd---%@--",r.statusCode,r.allHeaderFields);
}];
NSURLConnection非同步請求(GET-代理)
步驟
1 確定請求路徑
2 創建請求對象
3 創建NSURLConnection對象並設置代理
4 遵守NSURLConnectionDataDelegate協議,並實現相應的代理方法
5 在代理方法中監聽網路請求的響應
設置代理的幾種方法
/*
設置代理的第一種方式:自動發送網路請求
[[NSURLConnection alloc]initWithRequest:request delegate:self];
*/
/*
設置代理的第二種方式:
第一個參數:請求對象
第二個參數:誰成為NSURLConnetion對象的代理
第三個參數:是否馬上發送網路請求,如果該值為YES則立刻發送,如果為NO則不會發送網路請求
NSURLConnection *conn = [[NSURLConnection alloc]initWithRequest:request delegate:self startImmediately:NO];
//調用該方法控制網路請求的發送
[conn start];
*/
//設置代理的第三種方式:使用類方法設置代理,會自動發送網路請求
NSURLConnection *conn = [NSURLConnection connectionWithRequest:request delegate:self];
//取消網路請求
//[conn cancel];
相關的代理方法
/*
1.當接收到伺服器響應的時候調用
第一個參數connection:監聽的是哪個NSURLConnection對象
第二個參數response:接收到的伺服器返回的響應頭信息
*/
- (void)connection:(nonnull NSURLConnection *)connection didReceiveResponse:(nonnull NSURLResponse *)response
/*
2.當接收到數據的時候調用,該方法會被調用多次
第一個參數connection:監聽的是哪個NSURLConnection對象
第二個參數data:本次接收到的服務端返回的二進位數據(可能是片段)
*/
- (void)connection:(nonnull NSURLConnection *)connection didReceiveData:(nonnull NSData *)data
/*
3.當服務端返回的數據接收完畢之後會調用
通常在該方法中解析伺服器返回的數據
*/
-(void)connectionDidFinishLoading:(nonnull NSURLConnection *)connection
/*4.當請求錯誤的時候調用(比如請求超時)
第一個參數connection:NSURLConnection對象
第二個參數:網路請求的錯誤信息,如果請求失敗,則error有值
*/
- (void)connection:(nonnull NSURLConnection *)connection didFailWithError:(nonnull NSError *)error
其它
01 關於消息彈窗第三方框架的使用
SVProgressHUD
02 字元串截取相關方法
- (NSRange)rangeOfString:(NSString *)searchString;
- (NSString *)substringWithRange:(NSRange)range;
NSURLConnection發送POST請求
步驟
a.確定URL路徑
b.創建請求對象(可變對象)
c.修改請求對象的方法為POST,設置請求體(Data)
d.發送一個非同步請求
e.補充:設置請求超時,處理錯誤信息,設置請求頭(如獲取客戶端的版本等等,請求頭是可設置可不設置的)
代碼
//1.確定請求路徑
NSURL *url = [NSURL URLWithString:@"http://m.news.baidu.com/news"];
//2.創建請求對象
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//2.1更改請求方法
request.HTTPMethod = @"POST";
//2.2設置請求體
request.HTTPBody = [@"fr=mohome&ssid=0&from=1001703a&uid=&pu=sz%401320_1001%2Cta%40iphone_2_5.0_3_537&bd_page_type=1" dataUsingEncoding:NSUTF8StringEncoding];
//2.3請求超時
request.timeoutInterval = 5;
//2.4設置請求頭
[request setValue:@"ios 9.0" forHTTPHeaderField:@"User-Agent"];
//3.發送請求
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * __nullable response, NSData * __nullable data, NSError * __nullable connectionError) {
//4.解析伺服器返回的數據
if (connectionError) {
NSLog(@"--請求失敗-");
}else
{
NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
}
}];
URL中文轉碼問題
//1.確定請求路徑
NSString *urlStr = @"http://m.news.baidu.com/news?fr=mohome&ssid=0&from=1001703a&uid=&pu=sz%401320_1001%2Cta%40iphone_2_5.0_3_537&bd_page_type=1";
NSLog(@"%@",urlStr);
//中文轉碼操作
urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(@"%@",urlStr);
NSURL *url = [NSURL URLWithString:urlStr];
NSURLConnection
- 兩種為NSURLConnection設置代理方式的區別
//第一種設置方式:
//通過該方法設置代理,會自動的發送請求
// [[NSURLConnection alloc]initWithRequest:request delegate:self];
//第二種設置方式:
//設置代理,startImmediately為NO的時候,該方法不會自動發送請求
NSURLConnection *connect = [[NSURLConnection alloc]initWithRequest:request delegate:self startImmediately:NO];
//手動通過代碼的方式來發送請求
//註意該方法內部會自動的把connect添加到當前線程的RunLoop中在預設模式下執行
[connect start];
- 如何控制代理方法在哪個線程調用
//說明:預設情況下,代理方法會在主線程中進行調用(為了方便開發者拿到數據後處理一些刷新UI的操作不需要考慮到線程間通信)
//設置代理方法的執行隊列
[connect setDelegateQueue:[[NSOperationQueue alloc]init]];
- 開子線程發送網路請求的註意點,適用於自動發送網路請求模式
//在子線程中發送網路請求-調用startf方法發送
-(void)createNewThreadSendConnect1
{
//1.創建一個非主隊列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//2.封裝操作,並把任務添加到隊列中執行
[queue addOperationWithBlock:^{
NSLog(@"%@",[NSThread currentThread]);
//2-1.確定請求路徑
NSURL *url = [NSURL URLWithString:@"http://m.news.baidu.com/news?fr=mohome&ssid=0&from=1001703a&uid=&pu=sz%401320_1001%2Cta%40iphone_2_5.0_3_537&bd_page_type=1"];
//2-2.創建請求對象
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//2-3.使用NSURLConnection設置代理,發送網路請求
NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:request delegate:self startImmediately:YES];
//2-4.設置代理方法在哪個隊列中執行,如果是非主隊列,那麼代理方法將再子線程中執行
[connection setDelegateQueue:[[NSOperationQueue alloc]init]];
//2-5.發送網路請求
//註意:start方法內部會把當前的connect對象作為一個source添加到當前線程對應的runloop中
//區別在於,如果調用start方法開發送網路請求,那麼再添加source的過程中,如果當前runloop不存在
//那麼該方法內部會自動創建一個當前線程對應的runloop,並啟動。
[connection start];
}];
}
//在子線程中發送網路請求-自動發送網路請求
-(void)createNewThreadSendConnect2
{
NSLog(@"-----");
//1.創建一個非主隊列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//2.封裝操作,並把任務添加到隊列中執行
[queue addOperationWithBlock:^{
//2-1.確定請求路徑
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=dd&pwd=ww&type=JSON"];
//2-2.創建請求對象
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//2-3.使用NSURLConnection設置代理,發送網路請求
//註意:該方法內部雖然會把connection添加到runloop,但是如果當前的runloop不存在,那麼不會主動創建。
NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
//2-4.設置代理方法在哪個隊列中執行,如果是非主隊列,那麼代理方法將再子線程中執行
[connection setDelegateQueue:[[NSOperationQueue alloc]init]];
//2-5 創建當前線程對應的runloop,並開啟
[[NSRunLoop currentRunLoop]run];
}];
}