最近遇到两个bug都是与url encoding有关。
下载文件,假设地址是:
https://my.domain.com/download/我的图片.png
对应的代码为:
NSString *remoteURL = @"https://my.domain.com/download/我的图片.png";
// 如果url里含有中文,会返回nil,需要使用UTF8进行encoding
NSURL *url = [NSURL URLWithString: remoteURL];
if(url == nil){
url = [NSURL URLWithString:[remoteURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
}
其实,中文需要编码这个不算什么。更坑的是下面这段。因为之前用的是AFNetworking 2.x版本,为了适配苹果的IPv6,升级为3.x后,下载的代码是:
NSString *fileName = @"下载的图片.png";
NSString *documentDir = [NSHomeDirectory()
stringByAppendingPathComponent:@"Documents"];
NSString *localPath = [NSString stringWithFormat: @"%@/%@/%@", documentDir, @"downloadFiles", fileName];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFHTTPSessionManager *sessionManager = [AFHTTPSessionManager manager];
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy defaultPolicy];
securityPolicy.allowInvalidCertificates = YES;
securityPolicy.validatesDomainName = NO;
sessionManager.securityPolicy = securityPolicy;
NSURLSessionDownloadTask *downloadTask = [sessionManager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
// progress
} destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
// block的返回值,要求返回URL,返回的URL是文件的位置(已经encoding)
return [NSURL fileURLWithPath: localPath];
} completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
// 设置下载完成的操作, filePath是下载文件的位置
if(!error){
// download success
}else{
// download failed
}
}];
[downloadTask resume];
注意:destination block中返回的是存储目标路径,fileURLWithPath:会对localPath进行encoding。
因此,当再次打开已经保存在本地的图片(文档)时,直接使用localPath是不行的。原因就是本文开始提到的URLWithString:遇到中文会返回nil。所以,如果想要正常读取已经下载的文件,需要按照文章开头提到的方法对localPath进行encoding,或者直接使用completionHandler中返回的filePath。
那么,问题是可不可以直接不管是不是nil,直接进行encoding,然后该干嘛干嘛呢?
答案是不行,这要看下载时提供的地址是不是已经编码了,如果对已经encoding过的url再次进行encoding,就会导致encoding后的字符串中的 % 会被再次encoding,当然是不能被正确访问的.