網(wǎng)絡(luò)整理(四)——數(shù)據(jù)上傳

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];
    }
}

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容