1 POST上傳單個(gè)文件
重點(diǎn):1.單個(gè)文件上傳(四個(gè)步驟) 2.設(shè)置請求體格式
{
為什么要上傳文件:
- 以前很多服務(wù)器對(duì)上傳文件的大小有限制,PHP 限制是 2M
- 目前很多服務(wù)器不僅不限制大小,而且鼓勵(lì)上傳多個(gè)文件!
- 云服務(wù)器的普及!
- 軟件商希望獲得更多的用戶數(shù)據(jù)!
提示:abc 的目錄是用來保存上傳文件的,需要設(shè)置訪問權(quán)限!
<1> 文件上傳使用 POST 方法.
// 請求為可變請求
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 制定請求方法為 POST
request.HTTPMethod = @"POST";
<2> 設(shè)置請求頭,告訴服務(wù)器請求體中的內(nèi)容包含文件參數(shù).
[request setValue:@"multipart/form-data; boundary=kBoundary" forHTTPHeaderField:@"Content-Type"];
<3> 設(shè)置請求體(注意:必須嚴(yán)格按照格式設(shè)置).
{
// 上邊界
--boundary\r\n
Content-Disposition: form-data; name=userfile; filename=555\r\n
Content-Type: application/json\r\n\r\n
文件內(nèi)容的二進(jìn)制數(shù)據(jù)
// 下邊界
\r\n--boundary--
注意1:請求體內(nèi)容分為三個(gè)部分:
* 上邊界部分,告訴服務(wù)器要做數(shù)據(jù)上傳,包含了服務(wù)器的接收字段name=userfile,文件在服務(wù)器中保存的名稱filename=555,以及上傳文件的數(shù)據(jù)類型 application/json(需要嚴(yán)格按照字符串格式來設(shè)置)
* 上傳文件的數(shù)據(jù)部分(二進(jìn)制數(shù)據(jù))
* 下邊界部分,嚴(yán)格按照字符串格式來設(shè)置.
上邊界部分和下邊界部分的字符串,最后都要轉(zhuǎn)換成二進(jìn)制數(shù)據(jù),和文件部分的二進(jìn)制數(shù)據(jù)拼接在一起,作為請求體發(fā)送給服務(wù)器.
注意2:
* userfile => 負(fù)責(zé)上傳文件腳本中的 字段名,開發(fā)的時(shí)候,可以咨詢后端程序員
* filename => 將文件保存在服務(wù)器上的文件名稱
* Content-Type: 客戶端告訴服務(wù)器上傳文件的文件類型
注意3:
* 每一行末尾需要有一定的 \r\n
* 提示:有些服務(wù)器可以直接使用 \n,但是新浪微博如果使用 \n 上傳文件,服務(wù)器會(huì)返回“沒有權(quán)限”的錯(cuò)誤!
}
<4> 發(fā)送請求(用 NSURLConnection異步發(fā)送請求)
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
//
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@",string);
}];
}
2 多文件上傳
重點(diǎn):1.掌握多文件上傳的數(shù)據(jù)格式 2.學(xué)會(huì)封裝多文件上傳的方法
{
多文件上傳和單文件上傳的基本思路是一樣的,唯一的區(qū)別在于對(duì)請求體的封裝.
多文件的請求體部分格式1
{
// 第一個(gè)文件參數(shù)的上邊界
\r\n--boundary\r\n
Content-Disposition: form-data; name=userfile[]; filename=美女\r\n
Content-Type:image/jpeg\r\n\r\n
上傳文件的二進(jìn)制數(shù)據(jù)部分
// 第一個(gè)文件參數(shù)的下邊界
\r\n--boundary--
// 第二個(gè)文件參數(shù)的上邊界
\r\n--boundary\r\n
Content-Disposition: form-data; name=userfile[]; filename=JSON\r\n
Content-Type:text/plain\r\n\r\n
上傳文件的二進(jìn)制數(shù)據(jù)部分
// 第二個(gè)文件參數(shù)的下邊界
\r\n--boundary--
}
{
多文件上傳的請求體格式2
// 上邊界
// 第一個(gè)文件參數(shù)
\r\n--boundary\r\n
Content-Disposition: form-data; name=userfile[]; filename=美女\r\n
Content-Type:image/jpeg\r\n\r\n
上傳文件的二進(jìn)制數(shù)據(jù)部分
// 第二個(gè)文件參數(shù)
\r\n--boundary\r\n
Content-Disposition: form-data; name=userfile[]; filename=JSON\r\n
Content-Type:text/plain\r\n\r\n
上傳文件的二進(jìn)制數(shù)據(jù)部分
// 下邊界
\r\n--boundary--
}
}
3 獲取文件的 MIMEType
重點(diǎn): 能夠獲取文件的 MIMEType.
{
上傳文件的時(shí)候,需要告訴服務(wù)器文件類型(即Content-Type),這時(shí),需要獲取文件的 MIMEType.
獲取文件的 MIMEType 方法:加載文件時(shí),通過 response 獲得
{
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLResponse *response = nil;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL];
NSLog(@"%@",response.MIMEType);
}
response.MIMEType 即為 Content-Type 的類型.
如果不想告訴服務(wù)器具體的文件類型,可以使用這個(gè) Content-Type : application/octet-stream(8進(jìn)制流)
常見的 Content-Type 類型:
{
- 大類型/小類型
- text/plain
- image/jpg
- image/png
- image/gif
- text/html
- application/json
}
}
4 多文件 + 普通文本上傳
重點(diǎn): 學(xué)會(huì)拼接上傳文件數(shù)據(jù).
{
* 有些服務(wù)器可以在上傳文件的同時(shí),提交一些文本內(nèi)容給服務(wù)器
* 典型應(yīng)用:
<1>新浪微博: 上傳圖片的同時(shí),發(fā)送一條微博信息!
<2>購物評(píng)論: 購買商品之后發(fā)表評(píng)論的時(shí)候圖片+評(píng)論內(nèi)容!
多文件上傳的數(shù)據(jù)格式3
{
Content-Type: multipart/form-data; boundary=boundary
// ------ 以下內(nèi)容,是提供給服務(wù)器的二進(jìn)制數(shù)據(jù)格式
--boundary\r\n
Content-Disposition: form-data; name="userfile[]"; filename="aaa.txt"\r\n
Content-Type: application/octet-stream\r\n\r\n
文件二進(jìn)制數(shù)據(jù)
\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
文件二進(jìn)制數(shù)據(jù)
\r\n
--boundary\r\n
// username 是腳本文件接收參數(shù)的名稱
Content-Disposition: form-data; name="username"\r\n\r\n
普通文本二進(jìn)制數(shù)據(jù)
\r\n
--boundary--
// ------
以上部分,是發(fā)送給服務(wù)器的二進(jìn)制數(shù)據(jù)的組成格式(示例)
}
如果在 iOS 中,要實(shí)現(xiàn)POST上傳文件,需要按照上述格式,拼接數(shù)據(jù)!
因?yàn)?格式是 W3C 指定的標(biāo)準(zhǔn)格式,蘋果沒有做任何封裝!其他語言,都做了封裝!
以上三種數(shù)據(jù)拼接格式,需要大家了解并且能夠自己會(huì)拼接一種!
"第三方框架做文件上傳:
- AFN 能夠同時(shí)實(shí)現(xiàn)上傳"一個(gè)文件",有些格式的文件,用 AFN 無法上傳!
- ASI 能夠同時(shí)實(shí)現(xiàn)上傳多個(gè)文件,MRC的,2012年就停止更新了,設(shè)計(jì)的目標(biāo)平臺(tái), iOS 2.0/iOS 3.0 !
}
5 RESTful設(shè)計(jì)風(fēng)格
重點(diǎn): 了解RESTful設(shè)計(jì)風(fēng)格
{
為了簡化開發(fā)流程,使開發(fā)更加直觀,解讀更加容易,現(xiàn)在有一種非常流行的程序設(shè)計(jì)風(fēng)格---->RESTful設(shè)計(jì)風(fēng)格
RESTful設(shè)計(jì)風(fēng)格:
主要用于后端開發(fā),主要的表現(xiàn)形式為使用同一個(gè) URL,不同的 HTTP 訪問方法,表達(dá)不同的語義.
{
示例: http:/\/\www.xxx.com/product/123
-GET http:/\/\www.xxx.com/product/123 語義:從服務(wù)器"獲取"產(chǎn)品ID 為123的產(chǎn)品信息.
-POST http:/\/\www.xxx.com/product/123 語義:在服務(wù)器"新增"產(chǎn)品ID 為123的產(chǎn)品信息.
* 提交二進(jìn)制數(shù)據(jù),需要提交一個(gè) JSON 格式的二進(jìn)制數(shù)據(jù),后端程序員可以直接反序列化,得到 JSON 中得字典信息.
* POST JSON
-PUT http:/\/\www.xxx.com/product/123 語義:在服務(wù)器"修改"產(chǎn)品ID 為123的產(chǎn)品信息.
-DELETE http:/\/\www.xxx.com/product/123 語義:從服務(wù)器"刪除"產(chǎn)品ID 為123的產(chǎn)品信息.
RESTful設(shè)計(jì)風(fēng)格目前在國際上非常流行,國內(nèi)也逐漸開始普及.
作為前端程序員,只需要知道有這種設(shè)計(jì)風(fēng)格就可以.
}
}
6 AFN 上傳文件
重點(diǎn): 掌握 AFN 上傳文件的方法
{
// 1. 創(chuàng)建管理者
AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
// 2. 發(fā)送請求
[mgr POST:@"http://localhost/upload/upload.php" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
// formData :設(shè)置上傳文件所需要的參數(shù),兩種上傳方法:
// <1> 通過本地文件的 url 上傳
{
NSString *fromFile = @"/Users/likaining/Desktop/meinv.jpg";
NSURL *url = [NSURL URLWithString:@"file:///Users/likaining/Desktop/meinv.jpg"];
// url :需要上傳文件的文件路徑
// name :服務(wù)器接收的文件名.
// fileName: 文件在服務(wù)器中保存的名字
// mimeType : 文件類型
[formData appendPartWithFileURL:url name:@"userfile" fileName:@"meinv" mimeType:@"image/jpg" error:NULL];
}
// <2> 通過文件的 二進(jìn)制數(shù)據(jù) 上傳
{
NSData *data = [NSData dataWithContentsOfFile:zipFile];
[formData appendPartWithFileData:data name:@"userfile" fileName:@"meinv.zip" mimeType:@"gzip"];
}
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
// 上傳成功之后的回調(diào)
NSLog(@"%@",responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// 上傳失敗之后的回調(diào)
NSLog(@"失敗");
}];
}
7 監(jiān)測網(wǎng)絡(luò)狀態(tài)
重點(diǎn): 1.AFN 監(jiān)測網(wǎng)絡(luò)狀態(tài) 2.了解 Reachability 監(jiān)測網(wǎng)絡(luò)狀態(tài)
{
1. AFN 監(jiān)測網(wǎng)絡(luò)狀態(tài)
{
// 創(chuàng)建 網(wǎng)絡(luò)狀態(tài)管理者
AFNetworkReachabilityManager *mgr = [AFNetworkReachabilityManager sharedManager];
// 監(jiān)測網(wǎng)絡(luò)狀態(tài)的改變
[mgr setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
// 當(dāng)網(wǎng)絡(luò)狀態(tài)發(fā)生改變的時(shí)候調(diào)用這個(gè)block
switch (status) {
case AFNetworkReachabilityStatusReachableViaWiFi:
NSLog(@"WIFI網(wǎng)絡(luò)");
break;
case AFNetworkReachabilityStatusReachableViaWWAN:
NSLog(@"蜂窩網(wǎng)絡(luò)");
break;
case AFNetworkReachabilityStatusNotReachable:
NSLog(@"沒有網(wǎng)絡(luò)");
break;
case AFNetworkReachabilityStatusUnknown:
NSLog(@"未知網(wǎng)絡(luò)");
break;
default:
break;
}
}];
// 開始監(jiān)控
[mgr startMonitoring];
}
2.Reachability 監(jiān)測網(wǎng)絡(luò)狀態(tài)
{
// 注冊通知觀察者,網(wǎng)絡(luò)狀態(tài)改變時(shí),接收通知!
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(InternetStatusChanged) name:kReachabilityChangedNotification object:nil];
// 控制器銷毀時(shí),移除通知觀察者.
-(void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
// 根據(jù)當(dāng)前網(wǎng)絡(luò)狀態(tài),做出不同的響應(yīng).
- (void)InternetStatusChanged
{
NSLog(@"網(wǎng)絡(luò)狀態(tài)改變了");
if ([Reachability reachabilityForLocalWiFi].currentReachabilityStatus == ReachableViaWiFi) {
NSLog(@"Wifi 網(wǎng)絡(luò)");
}
if ([Reachability reachabilityForInternetConnection].currentReachabilityStatus == ReachableViaWWAN) {
NSLog(@"蜂窩移動(dòng)網(wǎng)絡(luò)");
}
if ([Reachability reachabilityForInternetConnection].currentReachabilityStatus == NotReachable)
{
NSLog(@"沒有網(wǎng)絡(luò)");
}
}
// 創(chuàng)建 Reachability 對(duì)象,開始監(jiān)測網(wǎng)絡(luò)狀態(tài)的改變
- (void)MonitorInternetStatus
{
Reachability *CZReachability = [Reachability reachabilityForInternetConnection];
[CZReachability startNotifier];
self.reachability = CZReachability;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self MonitorInternetStatus];
}
}
}