参考文章:http://www.cocoachina.com/bbs/read.php?tid=89985
协议
iOS 中上传文件需要自己实现http协议
在http协议中上传文件是有固定格式的,格式如下
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--
上面的每一个换行和空格都是必须的
Content-type: multipart/form-data,boundary=abcde
固定用法,在http协议中规定向服务器发送数据时需要使用multipart/form-data
规定了http中分隔线的标识,在http中只要见到--abcde这个字符串,就被理解为这是一个分隔符,abcde是一个随机字符串,具体长度限制我没有验证过,前面加--也是协议规定
--abcde
分隔线
content-disposition: form-data; name="field1"
Hello Boris!
这里声明了请求中的一个字段key = field1,value = Hello Boris!,这里两行之间的空行是必须的,是http协议的规定
--abcde
不同的字段需要用分隔线分开
content-disposition: form-data; name="pic"; filename="boris.png"
Content-Type: image/png
... contents of boris.png ...
这里声明文件字段,这里以图片为例
name是与后台规定的文件标识
filename是后台存储文件时的文件名
Content-Type是文件类型,这里是图片类型
... contents of boris.png ...是文件的二进制内容
iOS 实现
- (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;
//分界线标识符,这里构造了一个随机字符串
NSString *RANDOM_STRING = [NSString tc_getRandomStringWithType:TCRandomStringTypeLowercase | TCRandomStringTypeCapital | TCRandomStringTypeNumber
length:16];
//根据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);
//构造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];
//声明结束符 --randomString--
NSString *endBoundary = [[NSString alloc] initWithFormat:@"\r\n%@--",boundary];
//声明myRequestData,用来放入http body
NSMutableData *myRequestData = [NSMutableData data];
//将body字符串转换为UTF8编码
[myRequestData appendData:[body dataUsingEncoding:NSUTF8StringEncoding]];
//将image的data放入myRequestData
[myRequestData appendData:data];
//加入结束符
[myRequestData appendData:[endBoundary dataUsingEncoding:NSUTF8StringEncoding]];
//设置http header中Content-Type的值
NSString *content = [[NSString alloc] initWithFormat:@"multipart/form-data; boundary=%@",RANDOM_STRING];
//设置http header
[request setValue:content forHTTPHeaderField:@"Content-Type"];
//设置Content-Length
[request setValue:[NSString stringWithFormat:@"%lu",(unsigned long)[myRequestData length]] forHTTPHeaderField:@"Content-Length"];
//设置http body
[request setHTTPBody:myRequestData];
//设置http method
[request setHTTPMethod:@"POST"];
//建立连接
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}
备注
这个方法中没有处理大文件上传,一次性读取大文件的话内存会瞬间爆炸,解决这个问题可以在此基础上再做分片