iOS中URL的中文編碼和URL拼接字符串的問(wèn)題

一、URL中的中文編碼問(wèn)題

在開(kāi)發(fā)中,后端提供的接口中,有個(gè)圖片的url中帶有了中文,導(dǎo)致在創(chuàng)建NSURL時(shí)返回為nil。類似下面的代碼,如果你的SDWebImage下載圖片提示錯(cuò)誤Trying to load a nil url,可能就是因?yàn)橹形木幋a問(wèn)題造成的。

NSString *urlString = @"http://www.baidu.com/image?name=微信_(tái)123.jpg";
// 此時(shí)url為nil
NSURL *url = [NSURL URLWithString:urlString];

出現(xiàn)這種情況可以使用[NSString stringByAddingPercentEscapesUsingEncoding:]方法先將urlString轉(zhuǎn)碼為UTF8。

NSString *urlString = @"http://www.baidu.com/image?name=微信_(tái)123.jpg";
// url.absoluteString == "http://www.baidu.com/image?name=%E5%BE%AE%E4%BF%A1_123.jpg"
NSURL *url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

但是在我開(kāi)發(fā)的工程里,并不是所以u(píng)rl都沒(méi)有轉(zhuǎn)碼,已經(jīng)轉(zhuǎn)碼的url調(diào)用上面的方法會(huì)造成二次轉(zhuǎn)碼。

NSString *urlString = @"http://www.baidu.com/image?name=%E5%BE%AE%E4%BF%A1_123.jpg";
// url.absoluteString == "http://www.baidu.com/image?name=%25E5%25BE%25AE%25E4%25BF%25A1_123.jpg"
NSURL *url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

此時(shí)我們就需要使用下面的方法。

正確的使用方式

// 該方法可以根據(jù)urlString中的內(nèi)容判斷是否轉(zhuǎn)碼,沒(méi)有轉(zhuǎn)碼才進(jìn)行轉(zhuǎn)碼
static NSString * EncodeString(NSString * uncodeString) {
    return (NSString *) CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef) uncodeString, (CFStringRef)@"!$&'()*+,-./:;=?@_~%#[]",NULL,kCFStringEncodingUTF8));
}
NSString *urlString = @"http://www.baidu.com/image?name=微信_(tái)123.jpg";
NSString *urlString1 = @"http://www.baidu.com/image?name=%E5%BE%AE%E4%BF%A1_123.jpg";

// url.absoluteString == url1.absoluteString == "http://www.baidu.com/image?name=%25E5%25BE%25AE%25E4%25BF%25A1_123.jpg"
NSURL *url = EncodeString(urlString);
NSURL *url1 = EncodeString(urlString1);

CFURLCreateStringByAddingPercentEscapes("參數(shù)1","參數(shù)2","參數(shù)3","參數(shù)4","參數(shù)5");
//方法說(shuō)明
//首先返回一個(gè)CFStringRef
//參數(shù)3 不轉(zhuǎn)義字符 參數(shù)4 指定轉(zhuǎn)義字符
具體參數(shù)解釋 :
第一個(gè)參數(shù)是AllocatorRef –>內(nèi)存分配類型(內(nèi)存分配器下一節(jié)說(shuō)明)
第二個(gè)參數(shù)是CFStringRef –>待轉(zhuǎn)碼字符串
第三個(gè)參數(shù)是CFStringRef –>不轉(zhuǎn)義字符
第三個(gè)參數(shù)是CFStringRef –>指定轉(zhuǎn)義字符
第三個(gè)參數(shù)是CFStringEncoding –>編碼類型 KCFStringEncodingUTF8
這種方法有內(nèi)存泄漏一定要釋放:CFRelease(CFStringRef)
PS:CFBridgingRelease(CFStringRef) 釋放掉CFStringRef 并且轉(zhuǎn)化為NSString;

二、URL拼接字符串問(wèn)題

在工程中,因?yàn)楹蠖私涌诜祷氐膇mage都是大圖,所以需要前端在后面拼接參數(shù)thumb=1,所以想做一個(gè)通用的添加參數(shù)的方法。
url通常會(huì)有以下幾種形式:
1、https://www.baidu.com ----------------------------------------------noquery
2、https://www.baidu.com/act/index.html -------------------------------noquery
3、https://www.baidu.com/act/index.html? ------------------------------noquery but has ?
4、https://www.baidu.com/act/index.html?foo=bar ----------------------has query
5、https://www.baidu.com/act/index.html?foo1=bar1&foo2=bar2 --------has query
6、https://www.baidu.com/act/index.html?foo1=bar1&foo2=bar2#top ---has query and fragment
因?yàn)榇蟾庞猩厦鎺追N形式,所以直接用匹配的方式很復(fù)雜,不過(guò)幸好有系統(tǒng)方法可以幫我們分解url,然后合成url。

+ (NSURL *)url:(NSString *)urlString appendQuery:(NSString *)tmpQuery {
    if (urlString.length == 0 || tmpQuery.length == 0) {
        return nil;
    }
    NSURLComponents *components = [NSURLComponents componentsWithString:urlString];
    NSString *query = components.query;
    query = (query&&![query isEqualToString:@""])? [query stringByAppendingString:[NSString stringWithFormat:@"&%@",tmpQuery]] : tmpQuery;
    // components.query會(huì)過(guò)度編碼,已經(jīng)編碼的字符串會(huì)再次轉(zhuǎn)碼一次
    // components.query = query;
    // components.percentEncodedQuery不會(huì)是參數(shù)轉(zhuǎn)碼,但是需要保證設(shè)置的值不能有非法字符,所以需要保證query必須是轉(zhuǎn)碼后的字符串
    components.percentEncodedQuery = EncodeString(uncodeString);
    return components.URL;
}
在iOS9以后CFURLCreateStringByAddingPercentEscapes:失效了

所以可以使用下面的方法替換。

static NSString * EncodeString(NSString * uncodeString) {
    if (uncodeString.length == 0) {
        return nil;
    }
    // 先嘗試使用原始字符串創(chuàng)建url
    NSURL *url = [NSURL URLWithString:uncodeString];
    if (url == nil) {// 如果url為nil,說(shuō)明uncodeString中含有特殊字符串,則調(diào)用下面的方法進(jìn)行轉(zhuǎn)碼
        NSString *decodeString = (NSString *)CFBridgingRelease((__bridge CFTypeRef _Nullable)([uncodeString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]));
        url = [NSURL URLWithString:decodeString.length >0 ? decodeString : uncodeString];
    }
    return url.absoluteString;
}

參考內(nèi)容:
iOS-URL編解碼
再探URL拼接的坑

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容