URL編碼問題,這個(gè)文章不錯(cuò):
別再使用stringByAddingPercentEscapesUsingEncoding
當(dāng)遇到發(fā)送網(wǎng)絡(luò)請求的參數(shù)中有漢字的情況,很多人一股腦地使用stringByAddingPercentEscapesUsingEncoding:進(jìn)行轉(zhuǎn)義,這樣帶有漢字的urlString就會將每個(gè)漢字轉(zhuǎn)成相應(yīng)的unicode編碼對應(yīng)的3個(gè)%形式,這叫urlEncode(每個(gè)能寫后端的語言都有的方法),但是蘋果的stringByAddingPercentEscapesUsingEncoding:卻不是urlEncode。實(shí)際上我們使用的參數(shù)值可能會包含一些特殊的字符,如&,?這樣的字符,而Percent轉(zhuǎn)義已經(jīng)不能滿足需求了,如下面的例子:
NSString *queryWord = @"漢字&ss";
NSString *urlString = [NSString stringWithFormat:@"https://www.baidu.com/s?ie=UTF-8&wd=%@", queryWord];
NSString *escapedString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(@"%@", escapedString); // https://www.baidu.com/s?ie=UTF-8&wd=%E6%B1%89%E5%AD%97&ss
這是一個(gè)非常常見的情景,(之前公司項(xiàng)目的搜索中,也遇到過這種情況),這種被轉(zhuǎn)義之后的URL,服務(wù)端接收到的參數(shù)會使這樣的
["ie":"UTF-8", "wd":"漢字", "ss":nil]
即使你做如下的改進(jìn):(在請求之前將每個(gè)參數(shù)都轉(zhuǎn)義,再使用&拼接參數(shù)也無濟(jì)于事)
NSString *queryWord = @"漢字&ss";
NSString *escapedQueryWord = [queryWord stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *urlString = [NSString stringWithFormat:@"https://www.baidu.com/s?ie=UTF-8&wd=%@", escapedQueryWord];
NSLog(@"%@", urlString); // https://www.baidu.com/s?ie=UTF-8&wd=%E6%B1%89%E5%AD%97&ss
產(chǎn)生這種情況的原因是:百分號轉(zhuǎn)義不等于URLEncode
該編碼不同于URL編碼,由于不會對&字符編碼,因此不會改變URL參數(shù)的分隔。URL編碼會編碼&、?與其他標(biāo)點(diǎn)符號。如果查詢字符串包含了這些字符,那么需要實(shí)現(xiàn)一種更加徹底的編碼方法。
不過還好iOS7.0推出了stringByAddingPercentEncodingWithAllowedCharacters:方法
這個(gè)方法會對字符串進(jìn)行更徹底的轉(zhuǎn)義,但是需要傳遞一個(gè)參數(shù):這個(gè)參數(shù)是一個(gè)字符集,表示:在進(jìn)行轉(zhuǎn)義過程中,不會對這個(gè)字符集中包含的字符進(jìn)行轉(zhuǎn)義,而保持原樣保留下來。
這樣就可以使用它改造上面的代碼了:
NSString *queryWord = @"漢字&ss";
NSString *escapedQueryWord = [queryWord stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet letterCharacterSet]];
NSLog(@"%@", escapedQueryWord); // %E6%B1%89%E5%AD%97%26ss
NSString *urlString = [NSString stringWithFormat:@"https://www.baidu.com/s?ie=UTF-8&wd=%@", escapedQueryWord];
NSLog(@"%@", urlString); // https://www.baidu.com/s?ie=UTF-8&wd=%E6%B1%89%E5%AD%97%26ss
在上面的例子中傳遞參數(shù)[NSCharacterSet letterCharacterSet]來保證字母不被轉(zhuǎn)義。所以被轉(zhuǎn)義之后的參數(shù)值是:%E6%B1%89%E5%AD%97%26ss,這樣問題就解決了,但是有時(shí)候會遇到queryString中的表單域也需要轉(zhuǎn)義的情況,比如是一個(gè)表單數(shù)組如:
https://www.baidu.com/s?person[contact]=13801001234&person[address]=北京&habit[]=游泳&habit[]=騎行
這樣可以使用將key轉(zhuǎn)義,不過key中的[和]字符是不需要轉(zhuǎn)義的:可以自定義一個(gè)CharacterSet實(shí)現(xiàn)需求:
NSMutableCharacterSet *mutableCharSet = [[NSMutableCharacterSet alloc] init];
[mutableCharSet addCharactersInString:@"[]"]; // 允許'['和']'不被轉(zhuǎn)義
NSCharacterSet *charSet = mutableCharSet.copy;
NSMutableString *mutableString = [NSMutableString string];
for (unit in queryString) {
NSString *escapedField = [unit.field stringByAddingPercentEncodingWithAllowedCharacters:charSet];
NSString *escapedValue = [unit.value stringByAddingPercentEncodingWithAllowedCharacters:charSet];
[mutableString addFormat:@"%@=%@", escapedField, escapedValue];
}
這樣問題已經(jīng)圓滿解決了,美中不足的是:當(dāng)queryString非常多的時(shí)候你如何保證從queryString正確地提取出來每個(gè)unit呢,這個(gè)牽扯到復(fù)雜的字符串解析的問題。先不做討論。
下面還有對AFN的分析,就不貼了.
http://www.cnblogs.com/Mike-zh/p/5152073.html
URL編碼:
NSCharacterSet *allowedCharacters = [[NSCharacterSet characterSetWithCharactersInString:urlStr]invertedSet];//非URLstr字符集
NSString *encodedUrl = [urlStr stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacters];//對非URLstr字符集編碼