POST上傳

weixin_33670713發表於2015-12-19

/*----------------- 01 POST上傳單個檔案 -----------------*/

重點:1.單個檔案上傳(四個步驟) 2.設定請求體格式

{

為什麼要上傳檔案:

- 以前很多伺服器對上傳檔案的大小有限制,PHP 限制是 2M

- 目前很多伺服器不僅不限制大小,而且鼓勵上傳多個檔案!

- 雲伺服器的普及!

- 軟體商希望獲得更多的使用者資料!

提示:abc 的目錄是用來儲存上傳檔案的,需要設定訪問許可權!

<1> 檔案上傳使用 POST 方法.

// 請求為可變請求

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

// 制定請求方法為 POST

request.HTTPMethod = @"POST";

<2> 設定請求頭,告訴伺服器請求體中的內容包含檔案引數.

[request setValue:@"multipart/form-data; boundary=kBoundary" forHTTPHeaderField:@"Content-Type"];

<3> 設定請求體(注意:必須嚴格按照格式設定).

{

// 上邊界

--boundary\r\n

Content-Disposition: form-data; name=userfile; filename=555\r\n

Content-Type: application/json\r\n\r\n

檔案內容的二進位制資料

// 下邊界

\r\n--boundary--

注意1:請求體內容分為三個部分:

* 上邊界部分,告訴伺服器要做資料上傳,包含了伺服器的接收欄位name=userfile,檔案在伺服器中儲存的名稱filename=555,以及上傳檔案的資料型別 application/json(需要嚴格按照字串格式來設定)

* 上傳檔案的資料部分(二進位制資料)

* 下邊界部分,嚴格按照字串格式來設定.

上邊界部分和下邊界部分的字串,最後都要轉換成二進位制資料,和檔案部分的二進位制資料拼接在一起,作為請求體傳送給伺服器.

注意2:

* userfile => 負責上傳檔案指令碼中的 欄位名,開發的時候,可以諮詢後端程式設計師

* filename => 將檔案儲存在伺服器上的檔名稱

* Content-Type: 客戶端告訴伺服器上傳檔案的檔案型別

注意3:

* 每一行末尾需要有一定的 \r\n

* 提示:有些伺服器可以直接使用 \n,但是新浪微博如果使用 \n 上傳檔案,伺服器會返回“沒有許可權”的錯誤!

}

<4> 傳送請求(用 NSURLConnection非同步傳送請求)

[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {

//

NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

NSLog(@"%@",string);

}];

}

/*------------------------- 02 多檔案上傳 ------------------------*/

重點:1.掌握多檔案上傳的資料格式 2.學會封裝多檔案上傳的方法

{

多檔案上傳和單檔案上傳的基本思路是一樣的,唯一的區別在於對請求體的封裝.

多檔案的請求體部分格式1

{

// 第一個檔案引數的上邊界

\r\n--boundary\r\n

Content-Disposition: form-data; name=userfile[]; filename=美女\r\n

Content-Type:image/jpeg\r\n\r\n

上傳檔案的二進位制資料部分

// 第一個檔案引數的下邊界

\r\n--boundary--

// 第二個檔案引數的上邊界

\r\n--boundary\r\n

Content-Disposition: form-data; name=userfile[]; filename=JSON\r\n

Content-Type:text/plain\r\n\r\n

上傳檔案的二進位制資料部分

// 第二個檔案引數的下邊界

\r\n--boundary--

}

{

多檔案上傳的請求體格式2

// 上邊界

// 第一個檔案引數

\r\n--boundary\r\n

Content-Disposition: form-data; name=userfile[]; filename=美女\r\n

Content-Type:image/jpeg\r\n\r\n

上傳檔案的二進位制資料部分

// 第二個檔案引數

\r\n--boundary\r\n

Content-Disposition: form-data; name=userfile[]; filename=JSON\r\n

Content-Type:text/plain\r\n\r\n

上傳檔案的二進位制資料部分

// 下邊界

\r\n--boundary--

}

}

/*--------------------- 03 獲取檔案的 MIMEType ---------------------*/

重點: 能夠獲取檔案的 MIMEType.

{

上傳檔案的時候,需要告訴伺服器檔案型別(即Content-Type),這時,需要獲取檔案的 MIMEType.

獲取檔案的 MIMEType 方法:載入檔案時,通過 response 獲得

{

NSURLRequest *request = [NSURLRequest requestWithURL:url];

NSURLResponse *response = nil;

[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL];

NSLog(@"%@",response.MIMEType);

}

response.MIMEType 即為 Content-Type 的型別.

如果不想告訴伺服器具體的檔案型別,可以使用這個 Content-Type : application/octet-stream(8進位制流)

常見的 Content-Type 型別:

{

- 大型別/小型別

- text/plain

- image/jpg

- image/png

- image/gif

- text/html

- application/json

}

}

/*------------------- 04 多檔案 + 普通文字上傳 -----------------------*/

重點: 學會拼接上傳檔案資料.

{

* 有些伺服器可以在上傳檔案的同時,提交一些文字內容給伺服器

* 典型應用:

<1>新浪微博: 上傳圖片的同時,傳送一條微博資訊!

<2>購物評論: 購買商品之後發表評論的時候圖片+評論內容!

多檔案上傳的資料格式3

{

Content-Type: multipart/form-data; boundary=boundary

// ------ 以下內容,是提供給伺服器的二進位制資料格式

--boundary\r\n

Content-Disposition: form-data; name="userfile[]"; filename="aaa.txt"\r\n

Content-Type: application/octet-stream\r\n\r\n

檔案二進位制資料

\r\n

--boundary\r\n

Content-Disposition: form-data; name="userfile[]"; filename="aaa副本.txt"\r\n

Content-Type: application/octet-stream\r\n\r\n

檔案二進位制資料

\r\n

--boundary\r\n

// username 是指令碼檔案接收引數的名稱

Content-Disposition: form-data; name="username"\r\n\r\n

普通文字二進位制資料

\r\n

--boundary--

// ------

以上部分,是傳送給伺服器的二進位制資料的組成格式(示例)

}

如果在 iOS 中,要實現POST上傳檔案,需要按照上述格式,拼接資料!

因為:格式是 W3C 指定的標準格式,蘋果沒有做任何封裝!其他語言,都做了封裝!

以上三種資料拼接格式,需要大家瞭解並且能夠自己會拼接一種!

"第三方框架做檔案上傳:

- AFN 能夠同時實現上傳"一個檔案",有些格式的檔案,用 AFN 無法上傳!

- ASI 能夠同時實現上傳多個檔案,MRC的,2012年就停止更新了,設計的目標平臺, iOS 2.0/iOS 3.0 !

}

/*---------------------- 05 RESTful設計風格 ----------------------*/

重點: 瞭解RESTful設計風格

{

為了簡化開發流程,使開發更加直觀,解讀更加容易,現在有一種非常流行的程式設計風格---->RESTful設計風格

RESTful設計風格:

主要用於後端開發,主要的表現形式為使用同一個 URL,不同的 HTTP 訪問方法,表達不同的語義.

{

示例: http:/\/\www.xxx.com/product/123

-GET http:/\/\www.xxx.com/product/123  語義:從伺服器"獲取"產品ID 為123的產品資訊.

-POST http:/\/\www.xxx.com/product/123  語義:在伺服器"新增"產品ID 為123的產品資訊.

* 提交二進位制資料,需要提交一個 JSON 格式的二進位制資料,後端程式設計師可以直接反序列化,得到 JSON 中得字典資訊.

* POST JSON

-PUT http:/\/\www.xxx.com/product/123  語義:在伺服器"修改"產品ID 為123的產品資訊.

-DELETE http:/\/\www.xxx.com/product/123  語義:從伺服器"刪除"產品ID 為123的產品資訊.

RESTful設計風格目前在國際上非常流行,國內也逐漸開始普及.

作為前端程式設計師,只需要知道有這種設計風格就可以.

}

}

/*-------------------- 06 AFN 上傳檔案 ---------------------*/

重點: 掌握 AFN 上傳檔案的方法

{   

 // 1. 建立管理者

    AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];       

 // 2. 傳送請求  

  [mgr POST:@"http://localhost/upload/upload.php" parameters:nil constructingBodyWithBlock:^(idformData) {

// formData :設定上傳檔案所需要的引數,兩種上傳方法:

// <1> 通過本地檔案的 url 上傳

{

NSString *fromFile = @"/Users/likaining/Desktop/meinv.jpg";

NSURL *url = [NSURL URLWithString:@"file:///Users/likaining/Desktop/meinv.jpg"];

// url :需要上傳檔案的檔案路徑

// name :伺服器接收的檔名.

// fileName: 檔案在伺服器中儲存的名字

// mimeType : 檔案型別

[formData appendPartWithFileURL:url name:@"userfile" fileName:@"meinv" mimeType:@"image/jpg" error:NULL];

}

// <2> 通過檔案的 二進位制資料 上傳

{

NSData *data = [NSData dataWithContentsOfFile:zipFile];

[formData appendPartWithFileData:data name:@"userfile" fileName:@"meinv.zip" mimeType:@"gzip"];

}

} success:^(AFHTTPRequestOperation *operation, id responseObject) {

// 上傳成功之後的回撥

NSLog(@"%@",responseObject);

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {

//  上傳失敗之後的回撥

NSLog(@"失敗");

}];

}

/*--------------------- 07 監測網路狀態 ---------------------*/

重點: 1.AFN 監測網路狀態  2.瞭解 Reachability 監測網路狀態

{

1. AFN 監測網路狀態

{

// 建立 網路狀態管理者

AFNetworkReachabilityManager *mgr = [AFNetworkReachabilityManager sharedManager];

// 監測網路狀態的改變

[mgr setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {

// 當網路狀態發生改變的時候呼叫這個block

switch (status) {

case AFNetworkReachabilityStatusReachableViaWiFi:

NSLog(@"WIFI網路");

break;

case AFNetworkReachabilityStatusReachableViaWWAN:

NSLog(@"蜂窩網路");

break;

case AFNetworkReachabilityStatusNotReachable:

NSLog(@"沒有網路");

break;

case AFNetworkReachabilityStatusUnknown:

NSLog(@"未知網路");

break;

default:

break;

}

}];

// 開始監控

[mgr startMonitoring];

}

2.Reachability 監測網路狀態

{

// 註冊通知觀察者,網路狀態改變時,接收通知!

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(InternetStatusChanged) name:kReachabilityChangedNotification object:nil];

// 控制器銷燬時,移除通知觀察者.

-(void)dealloc

{

[[NSNotificationCenter defaultCenter] removeObserver:self];

}

// 根據當前網路狀態,做出不同的響應.

- (void)InternetStatusChanged

{

NSLog(@"網路狀態改變了");

if ([Reachability reachabilityForLocalWiFi].currentReachabilityStatus == ReachableViaWiFi) {

NSLog(@"Wifi 網路");

}

if ([Reachability reachabilityForInternetConnection].currentReachabilityStatus == ReachableViaWWAN) {

NSLog(@"蜂窩行動網路");

}

if ([Reachability reachabilityForInternetConnection].currentReachabilityStatus == NotReachable)

{

NSLog(@"沒有網路");

}

}

// 建立 Reachability 物件,開始監測網路狀態的改變

- (void)MonitorInternetStatus

{

Reachability *CZReachability = [Reachability reachabilityForInternetConnection];

[CZReachability startNotifier];

self.reachability = CZReachability;

}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

{

[self MonitorInternetStatus];

}

}

}

相關文章