AFNetworking3.1.0源码分析(三)AFHTTPRequestSerializer 之AFQueryStringPair

来源:互联网 发布:精算师所需软件 编辑:程序博客网 时间:2024/06/05 18:21

介绍

在发送请求之前需要配置request的各项参数,比如请求内容的编码,AFNetWorking中使用AFQueryStringPair类用来对网络请求数据进行编码(百分号编码)遵循rfc3986,

 AFQueryStringPair类通过函数NSString * AFPercentEscapedStringFromString(NSString *string){}实现编码。


预备知识:


1:URL理编码:

URL理编码时(使用%编码)默认根据ASCII国际标准(0-127范围)根据分析iOS CFURL源码(https://opensource.apple.com/source/CF/CF-855.14/)可以看到static const unsigned char sURLValidCharacters[128] 变量,存放了系统允许的字符集。

2:对于URL字符集的支持,根据系统函数

[NSCharacterSet URLUserAllowedCharacterSet]
[NSCharacterSet URLHostAllowedCharacterSet]
[NSCharacterSet URLPasswordAllowedCharacterSet]
[NSCharacterSet URLPathAllowedCharacterSet]
[NSCharacterSet URLQueryAllowedCharacterSet]
[NSCharacterSet URLFragmentAllowedCharacterSet]

函数获得,获取出来的是一个NSCharacterSet 对象,系统未开放API显示字符集,我通过循环遍历0-127之间的字符是否存在当前的字符集对象中,整理出以下系统对URL 不同segment支持的字符集,拿URLQueryAllowedCharacterSet举例:

 NSMutableCharacterSet * URLQueryAllowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];    NSMutableArray *URLQueryAllowedCharacters = [NSMutableArray arrayWithCapacity:0];    for (int i = 0; i < 128; i++) {                NSString *string =[NSString stringWithFormat:@"%c",i];                if ([string rangeOfCharacterFromSet:URLQueryAllowedCharacterSet].location != NSNotFound) {                        [URLQueryAllowedCharacters addObject:string];                    };    }    NSLog(@"allowedCharacters = %@\n\n",[URLQueryAllowedCharacters componentsJoinedByString:@" "]);
其它的可以效仿上面的方式输出,最终所有的字符集输出如下:

2016-11-24 11:01:55.396 test2[1775:50836] -------------URLUserAllowedCharacterSet-------------2016-11-24 11:01:55.397 test2[1775:50836] allowedCharacters = ! $ & ' ( ) * + , - . 0 1 2 3 4 5 6 7 8 9 ; = A B C D E F G H I J K L M N O P Q R S T U V W X Y Z _ a b c d e f g h i j k l m n o p q r s t u v w x y z ~2016-11-24 11:01:55.398 test2[1775:50836] -------------URLPasswordAllowedCharacterSet-------------2016-11-24 11:01:55.399 test2[1775:50836] allowedCharacters = ! $ & ' ( ) * + , - . 0 1 2 3 4 5 6 7 8 9 ; = A B C D E F G H I J K L M N O P Q R S T U V W X Y Z _ a b c d e f g h i j k l m n o p q r s t u v w x y z ~2016-11-24 11:01:55.399 test2[1775:50836] -------------URLHostAllowedCharacterSet-------------2016-11-24 11:01:55.400 test2[1775:50836] allowedCharacters = ! $ & ' ( ) * + , - . 0 1 2 3 4 5 6 7 8 9 : ; = A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ ] _ a b c d e f g h i j k l m n o p q r s t u v w x y z ~2016-11-24 11:01:55.400 test2[1775:50836] -------------URLPathAllowedCharacterSet-------------2016-11-24 11:01:55.401 test2[1775:50836] allowedCharacters = ! $ & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : = @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z _ a b c d e f g h i j k l m n o p q r s t u v w x y z ~2016-11-24 11:01:55.401 test2[1775:50836] -------------URLQueryAllowedCharacterSet-------------2016-11-24 11:01:55.402 test2[1775:50836] allowedCharacters = ! $ & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; = ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z _ a b c d e f g h i j k l m n o p q r s t u v w x y z ~2016-11-24 11:01:55.403 test2[1775:50836] -------------URLFragmentAllowedCharacterSet-------------2016-11-24 11:01:55.403 test2[1775:50836] allowedCharacters = ! $ & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; = ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z _ a b c d e f g h i j k l m n o p q r s t u v w x y z ~


AFNetWorking对URL编码实现

1:编码实现(此实现可以单独作为一个扩展实现使用到自己的项目中)

NSString * AFPercentEscapedStringFromString(NSString *string) {        ① static NSString * const kAFCharactersGeneralDelimitersToEncode = @":#[]@";    ② static NSString * const kAFCharactersSubDelimitersToEncode = @"!$&'()*+,;=";        ③ NSMutableCharacterSet * allowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];    ④ [allowedCharacterSet removeCharactersInString:[kAFCharactersGeneralDelimitersToEncode stringByAppendingString:kAFCharactersSubDelimitersToEncode]];        ⑤ // FIXME: https://github.com/AFNetworking/AFNetworking/pull/3028       // return [string stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet];        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);                // To avoid breaking up character sequences such as         range = [string rangeOfComposedCharacterSequencesForRange:range];        NSString *substring = [string substringWithRange:range];        NSString *encoded = [substring stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet];        [escaped appendString:encoded];       ⑦ index += range.length;    }    return escaped;}
解释:

①和②根据rfc3986创建在URI中query部分进行百分号编码的字符

③获取iOS系统针对URI中query部分允许出现的字符集

④根据rfc的规范去除①和②中出现的字符,得到最终的在query部分可以出现的字符集(不被百分号编码)

⑤介绍了一个关于系统直接编码产生的bug,因为在query中可能会出现emoji等特殊字符,这些字符的在编码过程中出现问题,具体的介绍往后看⑥-⑦的介绍

⑥-⑦:因为iOS系统的字符串编码默认使用utf16,中文字符的长度是1,实际上是占用两个字节,对于emoji (表情符号)等特殊字符,这些字符的长度是4,在对其编码的时候需要按位进行,如果只是简单的取出每一位的字符,就会产生断字。因此需要使用字符串的rangeOfComposedCharacterSequencesForRange: 方法达到整取的效果,比如某个字符串中有一个英文字符和3个表情符号,长度(length)应该是13,这时候取长度10,就只能取一个英文字符和连个表情字符,达到整取的效果,不会产生断字,影响到编码,此处代码中有个 batchSize  设置为50,是个默认值,这个地方你也可以这是10,或者100。主要是为了而快速的取值,算是一个策略值吧


0 0
原创粉丝点击