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

介绍

在发送请求之前需要配置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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值