使用NSURLSession通过FTP加载文件失败问题求助
NSURLSession FTP下载失败:"the requested url is not found on this server" 解决方法
核心问题分析
你的代码里有几个关键错误,直接导致了服务器返回路径不存在的错误:
FTP URL格式错误
你写的URL中,IP地址后面多了一个多余的冒号(比如ftp://121.122.0.200:/usr/path/file.json),正确的FTP URL格式是ftp://user:pwd@host/path,不指定端口时host后不需要冒号。这个错误会让服务器解析出错误的文件路径。方法1逻辑完全颠倒
方法1用了NSURLSessionUploadTask和PUT请求,这是上传文件的逻辑,和你要实现的下载功能完全反向。方法2凭证存储未初始化
方法2里的cred_storage是未初始化的空对象,调用setCredential不会生效,必须使用系统共享的凭证存储实例。
修正后的下载实现(两种可选方式)
方式1:URL中直接携带凭证(简单直接)
// 修正URL:去掉IP后的冒号,正确拼接用户名密码 NSURL *ftpURL = [NSURL URLWithString:@"ftp://user:pwd@121.122.0.200/usr/path/file.json"]; // 配置会话 NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; sessionConfig.allowsCellularAccess = YES; // 创建带代理的会话(需实现下载回调) NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil]; // 启动下载任务 NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:ftpURL]; [downloadTask resume];
方式2:使用凭证存储管理(适合分离凭证的场景)
NSURL *ftpURL = [NSURL URLWithString:@"ftp://121.122.0.200/usr/path/file.json"]; NSString *username = @"xxxx"; NSString *password = @"xxxx"; // 初始化保护空间 NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc] initWithHost:ftpURL.host port:[ftpURL.port integerValue] protocol:ftpURL.scheme realm:nil authenticationMethod:NSURLAuthenticationMethodDefault]; // 创建会话凭证 NSURLCredential *credential = [NSURLCredential credentialWithUser:username password:password persistence:NSURLCredentialPersistenceForSession]; // 使用系统共享的凭证存储 NSURLCredentialStorage *credStorage = [NSURLCredentialStorage sharedCredentialStorage]; [credStorage setCredential:credential forProtectionSpace:protectionSpace]; // 配置并启动会话 NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; sessionConfig.URLCredentialStorage = credStorage; sessionConfig.allowsCellularAccess = YES; NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil]; NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:ftpURL]; [downloadTask resume];
必备的代理回调实现
记得实现NSURLSessionDownloadDelegate的方法来处理下载结果:
// 下载完成后处理临时文件 - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location { NSString *docsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; NSURL *destURL = [NSURL fileURLWithPath:[docsDir stringByAppendingPathComponent:@"file.json"]]; NSError *error; [[NSFileManager defaultManager] moveItemAtURL:location toURL:destURL error:&error]; if (error) { NSLog(@"文件保存失败:%@", error.localizedDescription); } } // 处理下载错误 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { if (error) { NSLog(@"下载出错:%@", error.localizedDescription); } }
补充说明
SCP基于SSH协议,和FTP是完全不同的协议,服务器同时支持两种协议不代表URL格式通用,必须严格遵循FTP的URL规范。
内容的提问来源于stack exchange,提问作者Code cracker
相关产品推荐
相关产品推荐

