一、问题点
iOS7以上系统中, 对路径编码的方法是
URLString = [URLString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
这个方法在一般一说都是没有问题的,但是如果是在路径的pathCompnets中包含了特殊字符如"#"的情况下, 这个“#”会被编码成“%23”,导致网页404:资源未找到
查找问题原因:
/*
产生问题的原因:
* H5端开发人员对“?”后面的参数进行取值时,取到的值会解码,不会有问题;
* 但是如果路径上有特殊字符,那在访问网页的时候URL的pathCompenents部分,因为H5没有自己做编码处理,会导致找不到路径404错误:
解决思路:
1. 只对路径里面的参数部分进行编码,其他部分不编码
2. 截取?往后的字符进行编码
*/
NSString *URLString1 = @"https://qr.ysepay.com/h5agency/#/shenzhen";
NSURL *URL_notEncode1 = [NSURL URLWithString:URLString1];
NSString *URLString_encode1 = [URLString1 stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
NSURL *URL_Encode1 = [NSURL URLWithString:URLString_encode1];
NSLog(@"URL_notEncode1 = %@\nURLString_encode1=%@", URL_notEncode1.absoluteString, URL_Encode1.absoluteString);
// 结论:没有中文时可以使用系统的方法生成URL
NSString *URLString2 = @"https://qr.ysepay.com/h5agency/#/shenzhen?category=电子商务&shopOwner=赵云#wer";
NSURL *URL_notEncode2 = [NSURL URLWithString:URLString2];
NSString *URLString_encode2 = [URLString2 stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
NSURL *URL_Encode2 = [NSURL URLWithString:URLString_encode2];
NSLog(@"URL_notEncode2 = %@\nURLString_encode2=%@", URL_notEncode2.absoluteString, URL_Encode2.absoluteString);
// 结论:有中文时需要先编码再使用系统的方法生成URL,但是如果pathCompenents中含有“#”等特殊的字符时,也会被编码导致网页404
NSString *URLString3 = URLString2;
NSString *lastPathComponent = URLString2.lastPathComponent;// 如果是lastPathComponent,则“?”后面必然是参数
NSRange queryRange = [lastPathComponent rangeOfString:@"?"];//
if (queryRange.location != NSNotFound && queryRange.length > 0) {
NSString *queryOrignal = [lastPathComponent substringWithRange:NSMakeRange(queryRange.location+1, lastPathComponent.length -queryRange.location-1)];
NSString *queryEncode = [queryOrignal stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
NSString *lastPathComponentEncode = [lastPathComponent stringByReplacingOccurrencesOfString:queryOrignal withString:queryEncode];
URLString3 = [URLString2.stringByDeletingLastPathComponent stringByAppendingPathComponent:lastPathComponentEncode];
}
NSURL *correctURL = [NSURL URLWithString:URLString3];
// 结论:对参数部分进行编码后再生成URL即可
NSLog(@"correctURL=%@", correctURL);
二、解决方法
可以利用runtime的特性,交换系统的URLWithString:方法,具体代码如下
+ (void)load
{
Method orignalMethod = class_getClassMethod(self, @selector(URLWithString:));
Method exchangeMethod = class_getClassMethod(self, @selector(ys_URLWithString:));
method_exchangeImplementations(orignalMethod, exchangeMethod);
}
+ (instancetype)ys_URLWithString:(NSString *)URLString
{
if (URLString.length > 0) {// 中文转码
// 检查有没有进行过编码,有编码的情况下不再进行编码
// 取参数部分进行编码
NSString *URLString2 = [URLString stringByRemovingPercentEncoding];
NSString *lastPathComponent = URLString2.lastPathComponent;// 如果是lastPathComponent,则“?”后面必然是参数
NSRange queryRange = [lastPathComponent rangeOfString:@"?"];//
if (queryRange.location != NSNotFound && queryRange.length > 0) {
NSString *queryOrignal = [lastPathComponent substringWithRange:NSMakeRange(queryRange.location+1, lastPathComponent.length -queryRange.location-1)];
NSString *queryEncode = [queryOrignal stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
NSString *lastPathComponentEncode = [lastPathComponent stringByReplacingOccurrencesOfString:queryOrignal withString:queryEncode];
NSString *URLString3 = [URLString2.stringByDeletingLastPathComponent stringByAppendingPathComponent:lastPathComponentEncode];
URLString = URLString3;
}
return [self ys_URLWithString:URLString];
}
return nil;
}
延伸知识
根据网络标准RFC 1738,路径中有特殊字符的情况下,需要使用编码才可以用作URL
网络标准RFC 1738
“只有字母和数字[0-9a-zA-Z]、一些特殊符号“$-_.+!*'(),”[不包括双引号]、以及某些保留字,才可以不经过编码直接用于URL。”
建议看一下这个博客
https://blog.csdn.net/chenlycly/article/details/51820727