一、具體問題 開發的過程中,發現某個界面部分圖片的顯示出現了問題只顯示占點陣圖片,取出圖片的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的鍵值對就可以了