post 上傳文件(不用框架: 未完)

前言叨逼叨

  • iOS上傳文件,可能有很多第三方的框架之類的,比如AFN或者Alamofire之類的框架,但是今天要談?wù)摰氖窃腁PI是如何進(jìn)行文件上傳。

兵馬未動(dòng)糧草先行

  • 首先明確幾點(diǎn),上傳是用post實(shí)現(xiàn)的,另外服務(wù)器要提供好上傳的接口
  • 上傳的類型包括單個(gè)文件,多個(gè)文件,或者JSON或者自定義對(duì)象等等
  • 總思路:
    • 手動(dòng)拼接請(qǐng)求頭
    • 將要上傳的內(nèi)容轉(zhuǎn)換為二進(jìn)制數(shù)據(jù),并將其拼接到請(qǐng)求體中

一些必要的參數(shù)

  • application/x-www-form-urlencoded
    • 主要向服務(wù)器提交用戶隱私相關(guān)的信息
    • 瀏覽器支持
  • multipart/form-data
    • 向服務(wù)器上傳小文件
    • 瀏覽器支持
  • application/json
    • 向后臺(tái)服務(wù)器提交結(jié)構(gòu)化數(shù)據(jù)
    • RESTful 設(shè)計(jì)風(fēng)格需要
  • text/xml
    • 向后臺(tái)服務(wù)器提交結(jié)構(gòu)化數(shù)據(jù)
    • RESTful 設(shè)計(jì)風(fēng)格需要

具體實(shí)現(xiàn)

上傳單個(gè)文件

  • 請(qǐng)求格式
Content-Type: multipart/form-data; boundary(分隔線)=(可以隨便寫,ASCII,字母和數(shù)字)
  • 數(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--
  • 說(shuō)明

    • userfile:負(fù)責(zé)上傳文件腳本中的 字段名,開發(fā)的時(shí)候,可以咨詢后端程序員

    • filename:將文件保存在服務(wù)器上的文件名稱

    • Content-Type:客戶端告訴服務(wù)器上傳文件的文件類型

      • text/plain
      • image/jpg
      • image/png
      • image/gif
      • text/html
      • application/json
      • application/octet-stream(8進(jìn)制流),如果不想告訴服務(wù)器具體的文件類型,可以使用這個(gè) Content-Type
    • 注意:每一行末尾需要有一定的 \r\n

    • 提示:有些服務(wù)器可以直接使用 \n,但是新浪微博如果使用 \n 上傳文件,服務(wù)器會(huì)返回“沒(méi)有權(quán)限”的錯(cuò)誤!

代碼實(shí)現(xiàn)

生成 formData 二進(jìn)制數(shù)據(jù)

#define boundary    @"itheima-upload"

///  生成 formData 二進(jìn)制數(shù)據(jù)
///
///  @param fieldName 服務(wù)器字段名
///  @param fileName  文件名
///  @param fileData  上傳文件二進(jìn)制數(shù)據(jù)
///
///  @return formData 二進(jìn)制數(shù)據(jù)
- (NSData *)formData:(NSString *)fieldName fileName:(NSString *)fileName fileData:(NSData *)fileData {

    NSMutableData *dataM = [NSMutableData data];

    // 拼接數(shù)據(jù)
    NSMutableString *strM = [NSMutableString string];

    [strM appendFormat:@"--%@\r\n", boundary];
    [strM appendFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", fieldName, fileName];
    [strM appendString:@"Content-Type: application/octet-stream\r\n\r\n"];

    [dataM appendData:[strM dataUsingEncoding:NSUTF8StringEncoding]];
    [dataM appendData:fileData];

    NSString *tail = [NSString stringWithFormat:@"\r\n--%@--", boundary];
    [dataM appendData:[tail dataUsingEncoding:NSUTF8StringEncoding]];

    return dataM.copy;
}

上傳單個(gè)文件

///  上傳單個(gè)文件
///
///  @param fieldName 服務(wù)器自短命
///  @param fileName  文件名
///  @param fileData  上傳文件二進(jìn)制數(shù)據(jù)
- (void)uploadFile:(NSString *)fieldName fileName:(NSString *)fileName fileData:(NSData *)fileData {
    // 1. url - 負(fù)責(zé)上傳的腳本
    NSURL *url = [NSURL URLWithString:@"http://localhost/post/upload.php"];

    // 2. request
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    request.HTTPMethod = @"POST";

    NSString *typeValue = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
    [request setValue:typeValue forHTTPHeaderField:@"Content-Type"];

    request.HTTPBody = [self formData:fieldName fileName:fileName fileData:fileData];

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

        NSLog(@"%@", [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL]);
    }];
}

測(cè)試代碼

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

    NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"001.png" withExtension:nil];
    NSData *data = [NSData dataWithContentsOfURL:fileURL];

    [self uploadFile:@"userfile" fileName:@"abc" fileData:data];
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容