一.前言
之前對AFNetWorking二次封裝上傳圖片的方法是以文件流的方式上傳的,上傳文件有兩張方式:1.已文件流的方式上傳 2.將image轉成NSData,在進行base64加密上傳(NSString imageString = [data base64EncodedStringWithOptions:0];轉成base64字符串imageString,再傳給給后臺,在傳參中需要添加圖片的類型(@“png”或@“jpg”等))。兩種方式選擇哪一種,取決于后臺以哪種方式接受文件。對于第二種方式很簡單,第一種方式AFNetWoring也封裝好了,下面我們從最底層文件傳輸探討,也就是AFNetWoring內部是怎么實現文件流傳輸的。即探討一下
-(void)appendPartWithFileData:(NSData *)data
name:(NSString *)name
fileName:(NSString *)fileName
mimeType:(NSString *)mimeType;
到底是怎么實現的
二.單個文件傳輸(AFN在個別情況下不能完成,可直接用最底層方法傳輸)
/ /分割符:必須不能包含中文
#define CZBoundary @"baidu"
/**
* 上傳文件
*
* @param fileData fileData 上傳文件的二進制數據
* @param fieldName fieldName 上傳到服務器的字段名
* @param fileNamefileName上傳文件名
*/
- (void)uploadFile:(NSData *)fileData fieldName:(NSString
*)fieldName fileName:(NSString *)fileName
{
//url upload.php 是驗證上傳的腳本 它內部規定了保存在服務器哪個路徑 和傳入服務器的字段名 這是后臺給的路徑
NSURL *url = [NSURL URLWithString:@"http://192.168.51.9/post/upload.php"];
//request
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//設置請求方法
request.HTTPMethod = @"POST";
/* Content-Type
multipart/form-data; boundary=itcast*/
//設置contentType
[request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",CZBoundary] forHTTPHeaderField:@"Content-Type"];
//設置請求體
request.HTTPBody = [self fileData:fileData fieldName:fieldName fileName:fileName];
//發送請求
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(@"%@---%@",response,dict);
}];
}
/**
* 設置請求體二進制
*
* @param fileData fileData 上傳文件的二進制數據
* @param fieldName fieldName description
* @param fileNamefileName上傳文件名
*
* @return 請求體
*/
- (NSData *)fileData:(NSData *)fileData fieldName:(NSString
*)fieldName fileName:(NSString *)fileName
{
//創建一個可變二進制數據
NSMutableData *dataM = [NSMutableData data];
//創建一個可變字符串
NSMutableString *strM = [NSMutableString string];
[strM appendFormat:@"--%@\r\n",CZBoundary];
[strM appendFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n",fieldName,fileName];
[strM appendFormat:@"Content-Type: application/octet-stream\r\n\r\n"];
//將strM的內容拼接到dataM中
[dataM appendData:[strM dataUsingEncoding:NSUTF8StringEncoding]];
//拼接文件的二進制數據
[dataM appendData:fileData];
//拼接結尾標識
NSString *tail = [NSString stringWithFormat:@"\r\n--%@--",CZBoundary];
[dataM appendData:[tail dataUsingEncoding:NSUTF8StringEncoding]];
//拼接文件的二進制數據
return dataM;
}
-
調用示范
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent: (UIEvent *)event { NSString *filePath = [[NSBundle mainBundle]pathForResource:@"1.png" ofType:nil]; NSData *fileData = [NSData dataWithContentsOfFile:filePath]; [self uploadFile:fileData fieldName:@"userfile" fileName:@"1.png"]; }
三.多個文件傳輸
/**
* 上傳多個文件
*
* @param fileDict 多個文件字典
* @param fieldName 上傳到服務器的字段
* @param params 普通參數字典
*/
- (void)uploadFile:(NSDictionary *)fileDict fieldName:
(NSString *)fieldName params:(NSDictionary *)params
{
//url upload.php 是驗證上傳的腳本 它內部規定了保存在服務器哪個路徑 這是后臺給的路徑
NSURL *url = [NSURL URLWithString:@"http://localhost/post/upload-m.php"];
//request
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//設置請求方法
request.HTTPMethod = @"POST";
/* Content-Type
multipart/form-data; boundary=itcast*/
//設置contentType
[request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",CZBoundary] forHTTPHeaderField:@"Content-Type"];
//設置請求體
request.HTTPBody = [self fileData:fileDict fieldName:fieldName params:params];
//發送請求
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(@"%@---%@",response,dict);
}];
}
/**
* 設置請求體二進制
*
@param fileDict 多個文件字典
* @param fieldName 上傳到服務器的字段
* @param params 普通參數字典
*
* @return 請求體
*/
- (NSData *)fileData:(NSDictionary *)fileDict fieldName:
(NSString *)fieldName params:(NSDictionary *)params
{
//創建一個可變二進制數據
NSMutableData *dataM = [NSMutableData data];
//遍歷文件字典
[fileDict enumerateKeysAndObjectsUsingBlock:^(id _Nonnull fileName, id fileData, BOOL * _Nonnull stop) {
//創建一個可變字符串
NSMutableString *strM = [NSMutableString string];
[strM appendFormat:@"--%@\r\n",CZBoundary];
[strM appendFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n",fieldName,fileName];
[strM appendFormat:@"Content-Type: application/octet-stream\r\n\r\n"];
//將strM的內容拼接到dataM中
[dataM appendData:[strM dataUsingEncoding:NSUTF8StringEncoding]];
//拼接文件的二進制數據
[dataM appendData:fileData];
//拼接當前文件結尾標志
NSString *tail = [NSString stringWithFormat:@"\r\n--%@\r\n",CZBoundary];
[dataM appendData:[tail dataUsingEncoding:NSUTF8StringEncoding]];
}];
//遍歷普通參數 key是接受普通參數的字段 obj是普通參數內容
[params enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
//創建一個可變字符串
NSMutableString *strM = [NSMutableString string];
[strM appendFormat:@"Content-Disposition: form-data; name=%@\r\n\r\n",key];
[strM appendFormat:@"%@",obj];
[dataM appendData:[strM dataUsingEncoding:NSUTF8StringEncoding]];
}];
//拼接結尾標識
NSString *tail = [NSString stringWithFormat:@"\r\n--%@--",CZBoundary];
[dataM appendData:[tail dataUsingEncoding:NSUTF8StringEncoding]];
//
// //拼接文件的二進制數據
return dataM;
}
-
多個文件上傳調用示范
/ /分割符:必須不能包含中文 #define CZBoundary @"baidu" -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent: (UIEvent *)event { NSString *filePath1 = [[NSBundle mainBundle]pathForResource:@"1.png" ofType:nil]; NSData *fileData1 = [NSData dataWithContentsOfFile:filePath1]; NSString *filePath2 = [[NSBundle mainBundle]pathForResource:@"11.png" ofType:nil]; NSData *fileData2 = [NSData dataWithContentsOfFile:filePath2]; / /普通參數 NSString *username = @"file"; //接受文件數據的字段名:userfile[] 接受普通參數的字段 名:username //文件字典 NSDictionary *fileDict = @{@"1.png":fileData1,@"11.png":fileData2}; //普通參數字典 @"username"后臺給的傳入普通參數的字段名 value自己傳入的參數 NSDictionary *params = @{@"username":username}; //確定要傳入的文件 找后臺要路徑和傳入服務器的字段名 確定參數 [self uploadFile:fileDict fieldName:@"userfile[]" params:params]; }