美文网首页
iOS下载图片失败

iOS下载图片失败

作者: 菁欣陌陌 | 来源:发表于2018-09-06 10:06 被阅读107次

    一、具体问题

    开发的过程中,发现某个界面部分图片的显示出现了问题只显示占位图片,取出图片的url在浏览器却是能打开的,各种尝试甚至找同行的朋友帮忙在他们项目里展示都会存在问题,最终发现通过第三方框架SDWebImage或者YYWebImage下载带有逗号的url图片链接都会下载失败,在下载方法完成的回调block里面打印信息如下:

    Error Domain=NSURLErrorDomain Code=403 "(null)"
    

    现列举两个不能正常展示的图片url:

    http://img1.imgtn.bdimg.com/it/u=3044191397,2911599132&fm=27&gp=0.jpg
    
    http://img2.imgtn.bdimg.com/it/u=3509004173,840437551&fm=27&gp=0.jpg
    

    有兴趣的小伙伴可以拿到自己的项目里试试

    二、问题原因

    网上有小伙伴提出是因为缺少User-Agent用户代理导致的。只有设置了用户代理,才能访问到这张带有逗号的url图片。至于这个用户代理的格式,只要有值或者约定的特定格式字符串都可以。

    三、具体解决

    1.第三方框架YYWebImage

    找到YYWebImageManager.m文件,定位到设置http请求头的属性即_headers的地方,加入一个User-Agent的键值对,具体改动可以看下面的方法

    - (instancetype)initWithCache:(YYImageCache *)cache queue:(NSOperationQueue *)queue{
        self = [super init];
        if (!self) return nil;
        _cache = cache;
        _queue = queue;
        _timeout = 15.0;
        
        NSString *userAgent = @"";
        userAgent = [NSString stringWithFormat:@"%@/%@ (%@; iOS %@; Scale/%0.2f)", [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleExecutableKey] ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleIdentifierKey], [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"] ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleVersionKey], [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemVersion], [[UIScreen mainScreen] scale]];
        
        if (userAgent) {
            if (![userAgent canBeConvertedToEncoding:NSASCIIStringEncoding]) {
                NSMutableString *mutableUserAgent = [userAgent mutableCopy];
                if (CFStringTransform((__bridge CFMutableStringRef)(mutableUserAgent), NULL, (__bridge CFStringRef)@"Any-Latin; Latin-ASCII; [:^ASCII:] Remove", false)) {
                    userAgent = mutableUserAgent;
                }
            }
        }
    
        //带有逗号的图片url不显示的问题,重要的是设置代理才能解决
        if (YYImageWebPAvailable()) {
            _headers = @{ @"Accept" : @"image/webp,image/*;q=0.8", @"User-Agent" : userAgent};
        } else {
            _headers = @{ @"Accept" : @"image/*;q=0.8", @"User-Agent" : userAgent};
        }
        return self;
    }
    

    2.第三方框架SDWebImage

    找到SDWebImageDownloader.m文件,也是定位到设置http请求头的属性即_HTTPHeaders的地方,加入一个User-Agent的键值对,具体改动可以看下面的方法

    - (id)init {
        if ((self = [super init])) {
            _operationClass = [SDWebImageDownloaderOperation class];
            _shouldDecompressImages = YES;
            _executionOrder = SDWebImageDownloaderFIFOExecutionOrder;
            _downloadQueue = [NSOperationQueue new];
            _downloadQueue.maxConcurrentOperationCount = 6;
            _URLCallbacks = [NSMutableDictionary new];
            /***********************/
            NSString *userAgent = @"";
            userAgent = [NSString stringWithFormat:@"%@/%@ (%@; iOS %@; Scale/%0.2f)", [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleExecutableKey] ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleIdentifierKey], [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"] ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleVersionKey], [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemVersion], [[UIScreen mainScreen] scale]];
            
            if (userAgent) {
                if (![userAgent canBeConvertedToEncoding:NSASCIIStringEncoding]) {
                    NSMutableString *mutableUserAgent = [userAgent mutableCopy];
                    if (CFStringTransform((__bridge CFMutableStringRef)(mutableUserAgent), NULL, (__bridge CFStringRef)@"Any-Latin; Latin-ASCII; [:^ASCII:] Remove", false)) {
                        userAgent = mutableUserAgent;
                    }
                }
            }
            /***********************/
    #ifdef SD_WEBP
            _HTTPHeaders = [@{@"Accept": @"image/webp,image/*;q=0.8", userAgent : @"User-Agent"} mutableCopy];
    #else
            _HTTPHeaders = [@{@"Accept": @"image/*;q=0.8", userAgent : @"User-Agent"} mutableCopy];
    #endif
            _barrierQueue = dispatch_queue_create("com.hackemist.SDWebImageDownloaderBarrierQueue", DISPATCH_QUEUE_CONCURRENT);
            _downloadTimeout = 15.0;
        }
        return self;
    }
    

    或者是直接在UIImageView+WebCache.m文件中,在统一下载图片入口最前面添加如下代码

    - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock {
        /***********************/
        NSString *userAgent = @"";
        userAgent = [NSString stringWithFormat:@"%@/%@ (%@; iOS %@; Scale/%0.2f)", [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleExecutableKey] ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleIdentifierKey], [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"] ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleVersionKey], [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemVersion], [[UIScreen mainScreen] scale]];
        
        if (userAgent) {
            if (![userAgent canBeConvertedToEncoding:NSASCIIStringEncoding]) {
                NSMutableString *mutableUserAgent = [userAgent mutableCopy];
                if (CFStringTransform((__bridge CFMutableStringRef)(mutableUserAgent), NULL, (__bridge CFStringRef)@"Any-Latin; Latin-ASCII; [:^ASCII:] Remove", false)) {
                    userAgent = mutableUserAgent;
                }
            }
            
            [[SDWebImageDownloader sharedDownloader] setValue:userAgent forHTTPHeaderField:@"User-Agent"];
        }
        /***********************/
        [self sd_cancelCurrentImageLoad];
        
        ........省略原源码
    }
    

    3.其他第三方下载图片的框架

    直接全局搜索字符串"Accept",因为虽然缺少设置User-Agent用户代理,但是http请求头一般都会有设置"Accept",所以定位后,直接再加一个User-Agent的键值对就可以了

    相关文章

      网友评论

          本文标题:iOS下载图片失败

          本文链接:https://www.haomeiwen.com/subject/hcvtgftx.html