參考文章:http://www.cocoachina.com/bbs/read.php?tid=89985
協(xié)議
iOS 中上傳文件需要自己實(shí)現(xiàn)http協(xié)議
在http協(xié)議中上傳文件是有固定格式的,格式如下
Content-type: multipart/form-data, boundary=abcde
--abcde
content-disposition: form-data; name="field1"
Hello Boris!
--abcde
content-disposition: form-data; name="pic"; filename="boris.png"
Content-Type: image/png
... contents of boris.png ...
--abcde--
上面的每一個(gè)換行和空格都是必須的
Content-type: multipart/form-data,boundary=abcde
固定用法,在http協(xié)議中規(guī)定向服務(wù)器發(fā)送數(shù)據(jù)時(shí)需要使用multipart/form-data
規(guī)定了http中分隔線的標(biāo)識(shí),在http中只要見到--abcde這個(gè)字符串,就被理解為這是一個(gè)分隔符,abcde是一個(gè)隨機(jī)字符串,具體長(zhǎng)度限制我沒有驗(yàn)證過,前面加--也是協(xié)議規(guī)定
--abcde
分隔線
content-disposition: form-data; name="field1"
Hello Boris!
這里聲明了請(qǐng)求中的一個(gè)字段key = field1,value = Hello Boris!,這里兩行之間的空行是必須的,是http協(xié)議的規(guī)定
--abcde
不同的字段需要用分隔線分開
content-disposition: form-data; name="pic"; filename="boris.png"
Content-Type: image/png
... contents of boris.png ...
這里聲明文件字段,這里以圖片為例
name是與后臺(tái)規(guī)定的文件標(biāo)識(shí)
filename是后臺(tái)存儲(chǔ)文件時(shí)的文件名
Content-Type是文件類型,這里是圖片類型
... contents of boris.png ...是文件的二進(jìn)制內(nèi)容
iOS 實(shí)現(xiàn)
- (void)uploadFileWithURL:(NSString *)url
name:(NSString *)name
filename:(NSString *)filename
contentType:(NSString *)contentType
file:(NSData *)data
params:(NSDictionary *)params
success:(TCUploadFileMangerSuccess)success
fail:(TCUploadFileMangerFail)fail
{
self.success = success;
self.fail = fail;
//分界線標(biāo)識(shí)符,這里構(gòu)造了一個(gè)隨機(jī)字符串
NSString *RANDOM_STRING = [NSString tc_getRandomStringWithType:TCRandomStringTypeLowercase | TCRandomStringTypeCapital | TCRandomStringTypeNumber
length:16];
//根據(jù)url初始化request
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:10.0];
//分界線 --randomString
NSString *boundary = [[NSString alloc] initWithFormat:@"--%@",RANDOM_STRING];
//獲取圖片data
// UIImage *image = (UIImage *)file;
// NSData *data = UIImagePNGRepresentation(image);
//構(gòu)造http body字符串
NSMutableString *body = [[NSMutableString alloc] init];
NSArray *keys = [params allKeys];
for (id objc in keys) {
//添加分隔線 然后換行
[body appendFormat:@"%@\r\n",boundary];
//添加字段名稱 然后換兩行
[body appendFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n",objc];
//添加字段的值 然后換行
[body appendFormat:@"%@\r\n",params[objc]];
}
//添加分界線 然后換行
[body appendFormat:@"%@\r\n",boundary];
//聲明圖片字段
[body appendFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n",name,filename];
//聲明上傳文件的格式
[body appendFormat:@"Content-Type: %@\r\n\r\n",contentType];
//聲明結(jié)束符 --randomString--
NSString *endBoundary = [[NSString alloc] initWithFormat:@"\r\n%@--",boundary];
//聲明myRequestData,用來放入http body
NSMutableData *myRequestData = [NSMutableData data];
//將body字符串轉(zhuǎn)換為UTF8編碼
[myRequestData appendData:[body dataUsingEncoding:NSUTF8StringEncoding]];
//將image的data放入myRequestData
[myRequestData appendData:data];
//加入結(jié)束符
[myRequestData appendData:[endBoundary dataUsingEncoding:NSUTF8StringEncoding]];
//設(shè)置http header中Content-Type的值
NSString *content = [[NSString alloc] initWithFormat:@"multipart/form-data; boundary=%@",RANDOM_STRING];
//設(shè)置http header
[request setValue:content forHTTPHeaderField:@"Content-Type"];
//設(shè)置Content-Length
[request setValue:[NSString stringWithFormat:@"%lu",(unsigned long)[myRequestData length]] forHTTPHeaderField:@"Content-Length"];
//設(shè)置http body
[request setHTTPBody:myRequestData];
//設(shè)置http method
[request setHTTPMethod:@"POST"];
//建立連接
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}
備注
這個(gè)方法中沒有處理大文件上傳,一次性讀取大文件的話內(nèi)存會(huì)瞬間爆炸,解決這個(gè)問題可以在此基礎(chǔ)上再做分片