參考文獻:
- 文頂頂:iOS開發(fā)網(wǎng)絡(luò)篇
http://www.cnblogs.com/wendingding/p/3813572.html - iOS網(wǎng)絡(luò)開發(fā)編程之NSURLConnection詳解
http://www.2cto.com/kf/201503/380201.html
Dome地址
WeatherDome:https://github.com/BigTortoise/WeatherDome
注意:
本文以http://www.k780.com/api/weather.future# 天氣預(yù)報API接口為例敞映,展示NSURLConnection的GET和POST請求恩商。
1.iOS網(wǎng)絡(luò)層HTTP請求常用的庫:
- 蘋果原生
- NSURLConnection:最古老最經(jīng)典最直接的一種方案
- NSURLSession:功能比NSURLConnection更加強大尤蒿,蘋果目前比較推薦使用這種技術(shù)(iOS7開始出的技術(shù))
- 第三方框架
- AFNetworking:簡單易用,提供了基本夠用的常用功能萍嬉,維護和使用者多
- ASIHttpRequest:外號“HTTP終結(jié)者”乌昔,功能極其強大,可惜早已停止更新
2.HTTP通信過程
- 請求
- 請求頭:包含了對客戶端的環(huán)境描述壤追、客戶端請求信息等
GET /minion.png HTTP/1.1 //包含了請求方法磕道、請求資源路徑、HTTP協(xié)議版本 Host: 120.25.226.186:32812 //客戶端想訪問的服務(wù)器主機地址 User-Agent: Mozilla/5.0 //客戶端的類型行冰,客戶端的軟件環(huán)境 Accept: text/html,*/* //客戶端所能接收的數(shù)據(jù)類型 Accept-Language: zh-cn //客戶端的語言環(huán)境 Accept-Encoding: gzip //客戶端支持的數(shù)據(jù)壓縮格式
- 請求體:客戶端發(fā)給服務(wù)器的具體數(shù)據(jù)溺蕉,比如文件數(shù)據(jù)(POST請求才會有)
- 相應(yīng)
- 響應(yīng)頭:包含了對服務(wù)器的描述、對返回數(shù)據(jù)的描述
HTTP/1.1 200 OK //包含了HTTP協(xié)議版本悼做、狀態(tài)碼疯特、狀態(tài)英文名稱 Server:Apache-Coyote/1.1 //服務(wù)器的類型 Content-Type: image/jpeg //返回數(shù)據(jù)的類型 Content-Length: 56811 //返回數(shù)據(jù)的長度 Date: Mon, 23 Jun2014 12:54:52 GMT //響應(yīng)的時間
- 響應(yīng)頭:包含了對服務(wù)器的描述、對返回數(shù)據(jù)的描述
-
HTTP通信過程示意圖
HTTP通信過程.png -
常見響應(yīng)狀態(tài)碼
常見響應(yīng)狀態(tài)碼.png
3.NSURLConnection常用類
- NSURL:請求地址
- NSURLRequest:一個NSURLRequest對象就代表一個請求,它包含的信息有
- 一個NSURL對象
- 請求方法肛走、請求頭漓雅、請求體
- 請求超時
- ……
- NSMutableURLRequest:NSURLRequest的子類
- NSURLConnection
- 負責(zé)發(fā)送請求,建立客戶端和服務(wù)器的連接
- 發(fā)送數(shù)據(jù)給服務(wù)器朽色,并收集來自服務(wù)器的響應(yīng)數(shù)據(jù)
4.GET和POST請求
-
GET
- 所有參數(shù)拼接在URL后面邻吞,并且參數(shù)之間用&隔開
- 沒有請求體
- 一般用來查詢數(shù)據(jù)
-
POST
- 所有參數(shù)都放在
請求體
中 - 一般用來修改、增加葫男、刪除數(shù)據(jù)
- 所有參數(shù)都放在
NSURLConnection創(chuàng)建GET和POST請求
GET
// 請求路徑
NSString *urlString = @"http://api.k780.com:88/?app=weather.future&weaid=1&&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json";
urlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
// 創(chuàng)建URL
NSURL *url = [NSURL URLWithString:urlString];
// 創(chuàng)建請求
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 設(shè)置請求方法(默認就是GET請求)
request.HTTPMethod = @"GET";
- POST
// 請求路徑
NSString *urlString = @"http://520it.com/圖片";
urlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
// 創(chuàng)建URL
NSURL *url = [NSURL URLWithString:urlString];
// 創(chuàng)建請求
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 設(shè)置請求方法
request.HTTPMethod = @"POST";
// 設(shè)置請求體
request.HTTPBody = [@"name=張三&pwd=123" dataUsingEncoding:NSUTF8StringEncoding];
5.NSURLConnection的使用步驟
- 發(fā)送同步請求
+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error;
// 這個方法是阻塞式的抱冷,會在當(dāng)前線程發(fā)送請求
// 當(dāng)服務(wù)器的數(shù)據(jù)完全返回時,這個方法才會返回梢褐,代碼才會繼續(xù)往下執(zhí)行
- 發(fā)送異步請求-block
+ (void)sendAsynchronousRequest:(NSURLRequest*) request
queue:(NSOperationQueue*) queue
completionHandler:(void (^)(NSURLResponse* response, NSData* data, NSError* connectionError)) handler;
// 會自動開啟一個子線程去發(fā)送請求
// 當(dāng)請求完畢(成功\失斖凇),會自動調(diào)用handler這個block
// handler這個block會放到queue這個隊列中執(zhí)行
- 發(fā)送異步請求-delegate
- 創(chuàng)建NSURLConnection對象
// startImmediately==YES利职,創(chuàng)建完畢后趣效,自動發(fā)送異步請求
- (instancetype)initWithRequest:(NSURLRequest *)request delegate:(id)delegate startImmediately:(BOOL)startImmediately;
- (instancetype)initWithRequest:(NSURLRequest *)request delegate:(id)delegate; // 創(chuàng)建完畢后,自動發(fā)送異步請求
+ (NSURLConnection*)connectionWithRequest:(NSURLRequest *)request delegate:(id)delegate; // 創(chuàng)建完畢后猪贪,自動發(fā)送異步請求
- 發(fā)送請求
[connection start];
- 遵守
NSURLConnectionDataDelegate
協(xié)議跷敬,實現(xiàn)協(xié)議中的代理方法
// 當(dāng)接收到服務(wù)器的響應(yīng)時就會調(diào)用
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
// 每當(dāng)接收到服務(wù)器返回的數(shù)據(jù)時就會調(diào)用1次(數(shù)據(jù)量大的時候,這個方法就會被調(diào)用多次)
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
// 當(dāng)服務(wù)器的數(shù)據(jù)完全返回時調(diào)用(服務(wù)器的數(shù)據(jù)接收完畢)
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;
// 當(dāng)請求失敗的時候調(diào)用
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
- 取消請求
[connection cancel];
6.NSString和NSData的互相轉(zhuǎn)換
- NSString -> NSData
NSData *data = [@"520it.com" dataUsingEncoding:NSUTF8StringEncoding];
- NSData -> NSString
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
//發(fā)送請求給服務(wù)器热押,加載右側(cè)的數(shù)據(jù)
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"a"] = @"list";
params[@"c"] = @"subscribe";
params[@"category_id"] =@(c.id);
[[AFHTTPSessionManager manager] GET:@"http://api.budejie.com/api/api_open.php" parameters:params success:^(NSURLSessionDataTask *task, id responseObject) {
//字典轉(zhuǎn)模型數(shù)組
NSArray *users = [XJQRecommendUser objectArrayWithKeyValuesArray:responseObject[@"list"]];
//添加當(dāng)前類別對應(yīng)的用戶組
[c.users addObjectsFromArray:users];
//刷新表格
[self.detailVC reloadData];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
[SVProgressHUD showErrorWithStatus:@"加載數(shù)據(jù)失敗"];
}];
7.Dome演示
- Get同步和異步的兩個方法
//同步請求
- (void)sync
{
// 請求路徑
NSURL *url = [NSURL URLWithString:@"http://api.k780.com:88/?app=weather.future&weaid=1&&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json"];
// 創(chuàng)建請求對象
NSURLRequest *reuqest = [[NSURLRequest alloc] initWithURL:url];
// 發(fā)送請求
// sendSynchronousRequest阻塞式的方法西傀,等待服務(wù)器返回數(shù)據(jù)
NSHTTPURLResponse *response = nil;
NSError *error = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:reuqest returningResponse:&response error:&error];
// 解析服務(wù)器返回的數(shù)據(jù)
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"---%@", string);
}
// 異步請求
- (void)async
{
// 請求路徑
NSURL *url = [NSURL URLWithString:@"http://api.k780.com:88/?app=weather.future&weaid=1&&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json"];
// 創(chuàng)建請求對象
NSURLRequest *reuqest = [[NSURLRequest alloc] initWithURL:url];
// 發(fā)送請求
[NSURLConnection sendAsynchronousRequest:reuqest queue:[[NSOperationQueue alloc]init] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
// 解析服務(wù)器返回的數(shù)據(jù)
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@", string);
}];
}
- Post請求
- (void)asyncPost
{
// 請求路徑
NSURL *url = [NSURL URLWithString:@"http://api.k780.com:88"];
// 創(chuàng)建請求對象
NSMutableURLRequest *reuqest = [[NSMutableURLRequest alloc] initWithURL:url];
// 更改請求方法
reuqest.HTTPMethod = @"POST";
// 設(shè)置請求體
reuqest.HTTPBody = [@"app=weather.future&weaid=1&&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json" dataUsingEncoding:NSUTF8StringEncoding];
//設(shè)置請求超時
reuqest.timeoutInterval = 3;
// 設(shè)置請求頭
// [request setValue:@"iOS 9.0" forHTTPHeaderField:@"User-Agent"];
// 發(fā)送請求
[NSURLConnection sendAsynchronousRequest:reuqest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
if (connectionError) { // 比如請求超時
NSLog(@"----請求失敗");
} else {
NSLog(@"------%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}
}];
}
- 請求運行結(jié)果:
運行結(jié)果.png
應(yīng)用程序安全運輸了明文HTTP協(xié)議(http:/ /)資源負載是不安全的。暫時的異惩把ⅲ可以通過您的應(yīng)用程序的Info.plist文件配置拥褂。
解決辦法:在iOS9 beta1中,蘋果將原h(huán)ttp協(xié)議改成了https協(xié)議牙寞,使用 TLS1.2 SSL加密請求數(shù)據(jù)饺鹃。
在info.plist中添加
<key>NSAppTransportSecurity</key><dict>
<key>NSAllowsArbitraryLoads</key>
<true/></dict>
- 修改后運行結(jié)果:
正確運行結(jié)果.png
- 代理方法
- (void)delegateAysnc
{
// 0.請求路徑
NSURL *url = [NSURL URLWithString:@"http://api.k780.com:88/?app=weather.future&weaid=1&&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json"];
// 1.創(chuàng)建請求對象
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 2.創(chuàng)建連接對象
// [[NSURLConnection alloc] initWithRequest:request delegate:self];
// NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
// [conn start];
[NSURLConnection connectionWithRequest:request delegate:self];
// 取消
// [conn cancel];
}
#pragma mark - <NSURLConnectionDataDelegate> -- being
/**
* 接收到服務(wù)器的響應(yīng)
*/
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSLog(@"didReceiveResponse");
}
/**
* 接收到服務(wù)器的數(shù)據(jù)(如果數(shù)據(jù)量比較大莫秆,這個方法會被調(diào)用多次)
*/
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// 不斷拼接服務(wù)器返回的數(shù)據(jù)
NSLog(@"didReceiveData -- %zd", data.length);
}
/**
* 服務(wù)器的數(shù)據(jù)成功接收完畢
*/
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(@"connectionDidFinishLoading");
}
8.注意點
-發(fā)送Get請求時可能Url中會有中文,所有最好進行一次轉(zhuǎn)碼:
NSURL *url = [NSURL URLWithString:urlStr];