在OS X 10.9配置WebDAV服务器联合NSURLSessionUploadTask实现文件上传
iOS7推出的NSURLSession简化了NSURLConnection的文件上传和下载的工作,本文记录如何配置WebDAV服务以支持PUT方式的文件上传。
一. 配置WebDAV服务器
1. 修改httpd.conf
1> 打开终端,依次输入:
cd /etc/apache2/
sudo vi httpd.conf
2> 在vi中输入
查找httpd-dav.conf
3> 将该行最前面的 # 注释删除
4> 保存并退出
输入
2. 修改httpd-dav.conf
1> 在终端中依次输入:
cd /etc/apache2/extra
sudo vi httpd-dav.conf
2> 按照以下内容修改httpd-dav.conf中的内容
提示:仅修改了授权类型和用户密码文件两个位置
DavLockDB "/usr/var/DavLock"
Alias /uploads "/usr/uploads"
<directory "="" usr="" uploads"="">
Dav On
Order Allow,Deny
Allow from all
#用户的授权类型
AuthType Basic
AuthName DAV-upload
# You can use the htdigest program to create the password database:
# htdigest -c "/usr/user.passwd" DAV-upload admin
# 用户密码文件
AuthUserFile "/usr/webdav.passwd"
AuthDigestProvider file
# Allow universal read-access, but writes are restricted
require user admin
说明:
按照上述配置文件,可以通过URL-> http://localhost/uploads,将文件上传至/usr/uploads目录
上传文件所使用的用户名是:admin
3> 保存并退出
输入
3. 建立文件夹并配置文件
1> 创建admin的密码,在终端中输入:
sudo htpasswd -c /usr/webdav.passwd admin
然后输入admin的密码,密码文件会保存在/usr/webdav.passwd中
2> 设置webdav.passwd权限
sudo chgrp www /usr/webdav.passwd
3> 建立var文件夹,以保存DavLockDB相关文件
sudo mkdir -p /usr/var
sudo chown -R www:www /usr/var
4> 建立上传文件夹:uploads
sudo mkdir -p /usr/uploads
sudo chown -R www:www /usr/uploads
5> 重新启动Apache
sudo apachectl -k restart
4. 测试
打开Finder,在菜单中选择“前往"“连接服务器",在地址栏中输入: http://localhost/uploads
然后用户名admin及在终端设置的密码,连接至服务器,并测试更新文件。
二. 使用NSURLSessionUploadTask实现文件上传
- (IBAction)uploadFile
{
// 要上传的文件
UIImage *image = [UIImage imageNamed:@"123.jpg"];
NSData *imageData = UIImageJPEGRepresentation(image, 1.0f);
// 上传的文件名
NSString *urlString = @" http://localhost/uploads/demo.jpg";
urlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url];
// 使用PUT方法
[request setHTTPMethod: @"PUT"];
// 用户授权
NSString *basicAuthCredentials = [NSString stringWithFormat:@"%@:%@", @"admin", @"123"];
NSString *authValue = [NSString stringWithFormat:@"Basic %@", AFBase64EncodedStringFromString(basicAuthCredentials)];
[request setValue:authValue forHTTPHeaderField:@"Authorization"];
[request setHTTPBody: imageData];
[request setValue:@"image/jpg" forHTTPHeaderField:@"Content-Type"];
[request setValue:[NSString stringWithFormat:@"%d", [imageData length]] forHTTPHeaderField:@"Content-Length"];
// URLSession
NSURLSession *session = [NSURLSession sharedSession];
// 上传任务
NSURLSessionUploadTask *task = [session uploadTaskWithRequest:request fromData:imageData completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (!data) {
NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@ %@", result, response);
} else {
NSLog(@"upload ok!");
}
}];
[task resume];
}
另外,还需要一个对字符串进行Base64编码的方法,代码如下:
static NSString *AFBase64EncodedStringFromString(NSString *string)
{
NSData *data = [NSData dataWithBytes:[string UTF8String] length:[string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]];
NSUInteger length = [data length];
NSMutableData *mutableData = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
uint8_t *input = (uint8_t *)[data bytes];
uint8_t *output = (uint8_t *)[mutableData mutableBytes];
for (NSUInteger i = 0; i < length; i += 3) {
NSUInteger value = 0;
for (NSUInteger j = i; j < (i + 3); j++) {
value <<= 8;
if (j < length) {
value |= (0xFF & input[j]);
}
}
static uint8_t const kAFBase64EncodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
NSUInteger idx = (i / 3) * 4;
output[idx + 0] = kAFBase64EncodingTable[(value >> 18) & 0x3F];
output[idx + 1] = kAFBase64EncodingTable[(value >> 12) & 0x3F];
output[idx + 2] = (i + 1) < length ? kAFBase64EncodingTable[(value >> 6) & 0x3F] : '=';
output[idx + 3] = (i + 2) < length ? kAFBase64EncodingTable[(value >> 0) & 0x3F] : '=';
}
return [[NSString alloc] initWithData:mutableData encoding:NSASCIIStringEncoding];
}