欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

iOS下载图片失败

程序员文章站 2022-06-21 11:28:33
一、具体问题 开发的过程中,发现某个界面部分图片的显示出现了问题只显示占位图片,取出图片的url在浏览器却是能打开的,各种尝试甚至找同行的朋友帮忙在他们项目里展示都会存在问题,最终发现通过第三方框架SDWebImage或者YYWebImage下载带有逗号的url图片链接都会下载失败,在下载方法完成的 ......

一、具体问题  

  开发的过程中,发现某个界面部分图片的显示出现了问题只显示占位图片,取出图片的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的键值对就可以了