一、前言
字符串以url的形式传递给服务器时,有些字符是会被限制的。为了符合url的规范,这些被限制的字符,就需要被转义。比方说:把一个邮箱地址放入url就需要转义,因为邮箱地址中包含限制字符@
。
UrlEncode,主要是为了让url的参数可以被准确无误地传输。
二、哪些字符需要转义
在标准的url规范中,中文和很多别的字符是不允许出现在url中的。这些需要转义的字符,都将被替换成:%
+ 2位16进制数。
1、ASCII的控制字符
这些字符都是不可打印的,自然需要进行转义。
2、一些特殊字符
例如:emoji字符👴🏻👮🏽。特殊字符需要被转转义也是理所当然的。
3、与url分隔字符相同的字符
url中的分隔符包含主要分隔符:#[]@?/
和次要分隔符!$&'()*+,;=
。
url的query
参数和值,如果在分隔符的包含范围内,除了?
和/
外,都需要转义。例如:对于原始urlhttps://www.baidu.com?paramA=哈哈¶mB=&
来说,哈哈
和paramB=&
中的&
就需要参与转义。哈哈是中文,所以需要转义。&
在分隔符的包含范围内,所以也需要转义。如果不进行转义,后端收到后,会认为它是一个参数值,还是url本身的分隔符呢?
4、一些不安全的字符
例如:空格。为了避免歧义,需要被转化成+
或者%20
。具体转换成+
还是%20
主要依据不同的转换标准。
三、AFNetworking的转义过程
AFURLRequestSerialization
的源码很好地说明了转义的过程和规则:
//对string进行url转义
NSString * AFPercentEscapedStringFromString(NSString *string) {
//需要参与转义的分隔符
static NSString * const kAFCharactersGeneralDelimitersToEncode = @":#[]@"; // does not include "?" or "/" due to RFC 3986 - Section 3.4
static NSString * const kAFCharactersSubDelimitersToEncode = @"!$&'()*+,;=";//子分隔符
//从query参数可用的字符集中把上述分隔符去除,得到不用参与转义的字符集
NSMutableCharacterSet *allowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];
[allowedCharacterSet removeCharactersInString:[kAFCharactersGeneralDelimitersToEncode stringByAppendingString:kAFCharactersSubDelimitersToEncode]];
static NSUInteger const batchSize = 50;//每次转码的最大长度,修复对超长中文字符串转义会导致闪退的问题
NSUInteger index = 0;
NSMutableString *escaped = @"".mutableCopy;
while (index < string.length) {
NSUInteger length = MIN(string.length - index, batchSize);
NSRange range = NSMakeRange(index, length);
// 👴🏻👮🏽等emoji的长度不是一,为了避免原来的range切断emoji,对原来range扩展一下
range = [string rangeOfComposedCharacterSequencesForRange:range];
NSString *substring = [string substringWithRange:range];
NSString *encoded = [substring stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet];//除了不用参与转义的字符,其他字符都应该参与转义
[escaped appendString:encoded];
index += range.length;
}
return escaped;
}
复制代码
四、总结
把特殊字符转义成别的数据,使其不会和别的字符产生语义上的冲突,这就是需要UrlEncode的原因。