【问题标题】:Make an NSURL with an encoded plus (%2B)使用编码加号 (%2B) 创建一个 NSURL
【发布时间】:2009-05-22 15:30:52
【问题描述】:

我需要在 GET 请求中传递带有时区偏移量的时间戳,例如,

2009-05-04T11:22:00+01:00

这看起来像是接收 PHP 脚本的两个参数“2009-05-04T11:22:00”和“01:00”(我无法控制)。

NSURL 不编码加号,但如果我使用字符串创建 NSURL

2009-05-04T11:22:00%2B01:00

我最终得到的网址包含:

2009-05-04T11:22:00%252B01:00

有什么想法可以保留我编码的加号或只是简单地阻止 NSURL 编码任何东西?

【问题讨论】:

    标签: iphone url html-encode


    【解决方案1】:

    对我有用的是进行 UTF8 转换,然后用 %2B 替换 + 符号:

    NSString *urlString =
        [NSString stringWithFormat:@"%@/iphone/push/create?pn[token]=%@&pn[send_at]=%@",
         kHTTPURL, appDelegate.deviceAPNToken, [dateTimeToUse description]];
    
    urlString =
        [[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]
         stringByReplacingOccurrencesOfString:@"+" withString:@"%2B"];
    

    【讨论】:

    • 我不明白这怎么是正确的答案。这些问题询问如何创建正确的 NSURL 对象。如果此字符串用于创建 NSURL 对象,则 % 符号将再次编码为 %25。请澄清。
    • 这样就解决了问题。然而,这不是正确的解决方案,因为它只处理“+”而不是其他需要编码的字符。
    • 这对我不起作用。相反,我在创建 urlString 之前使用 Ric Santos 的答案对时间戳进行了编码。根据我的经验,我从未见过有人需要对参数名称、架构、域或 url 的其他部分进行编码。因此,最好单独对参数值进行编码。但是,如果有一个函数可以拆分 url,正确编码,然后将其重新组合在一起,那就太好了。我假设 stringByAddingPercentEscapesUsingEncoding 做到了这一点,但显然它在 + 号之类的情况下失败了。
    【解决方案2】:

    字符串应该是 URL 编码的。

    这里有一个对 NSString 有帮助的类别:

    NSString+Additions.h

    @interface NSString (Additions)
    
    - (NSString *)stringByURLEncoding;
    

    NSString+Additions.m

    #import "NSString+Additions.h"
    
    @implementation NSString (Additions)
    
    - (NSString *)stringByURLEncoding {
        return (__bridge NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
                                                               (CFStringRef)self,
                                                               NULL,
                                                               (CFStringRef)@"!*'\"();:@&=+$,/?%#[]% ",
                                                               CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding));
    }
    

    【讨论】:

      【解决方案3】:

      对要作为参数包含的文本使用NSStringstringByAddingPercentEscapesUsingEncoding: 方法。

      顾名思义,该方法将转换返回一个自动释放的字符串,其中包含一个 url-safe 版本的接收器。

      【讨论】:

      • 我试过了——它将“+”转换为“%2B”。然后 NSURL 对 '%' 进行编码,所以你最终得到 '%252B'
      • 很可能,您的 URL 有问题。你需要使用 NSURL 的URLWithString:
      • 并确保您没有在同一个字符串上调用该方法两次,否则它调用它两次编码您的结果字符串,从而将 % 编码为 %25 .还要确保你在任何地方都使用 NSUTF8Encoding。
      • 这根本行不通。 '+' 字符在 URL 中完全有效,不会被 NSURL 编码。如果你把它留在里面,它会作为一个单独的参数出现。最后,我不得不将时间戳转换为 GMT 并从字符串中删除时区偏移量。不漂亮,但还有其他东西可以继续……
      【解决方案4】:

      我认为我不妨提供我的解决方法作为答案,因为我认为原始问题没有很好的解决方案。

      加号 (+) 在 URL 中完全有效,因此我的解决方案是将时间转换为 GMT 并从字符串中删除时区/DST 偏移量。我将把它作为练习留给读者来确定下面的 secondsFromGMT 的值,因为在我的情况下,它总是相同的,因为我只对 Web 服务器生成的时间戳感兴趣。

      NSString *gmtWhen = [[self descriptionWithCalendarFormat:nil
                                 timeZone:[NSTimeZone
                                 timeZoneForSecondsFromGMT:secondsFromGMT
                           ] locale:nil] stringByReplacingOccurrencesOfString:@" +0000" withString:@""];
      

      【讨论】:

        【解决方案5】:

        使用 URLComponents (Swift 3) 时的解决方案:

        var params = ["email": "user+ios-default@example.com", "name": "John Brown"]
        var components = URLComponents(string: "http://www.example.com")!
        components.path = "/login"
        components.queryItems = params.map { URLQueryItem(name: $0, value: $1) }
        
        let url_NoFix = components.url!
        // http://www.example.com/login?name=John%20Brown&email=user+ios-default@example.com
        
        let cs = CharacterSet(charactersIn: "+").inverted
        let q =  components.percentEncodedQuery?.addingPercentEncoding(withAllowedCharacters: cs)
        components.percentEncodedQuery = q
        
        let url_Fixed = components.url!
        // http://www.example.com/login?name=John%20Brown&email=user%2Bios-default@example.com
        

        【讨论】:

          【解决方案6】:

          使用以下代码对字符串进行编码

          NSString *result = (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)self,NULL,(CFStringRef)@"+",kCFStringEncodingUTF8);

          这将对你的字符串进行编码,这将防止在 post 方法中发布数据时将 + 替换为 %2b

          【讨论】:

            【解决方案7】:

            要获得编码加号 (%2B)(适用于所有字符),请使用 CFURLCreateStringByAddingPercentEscapes as

            /**
             get parameterized url from url and query parameters.
             */
            +(NSString *)getParameterizedUrl:(NSString *)url withParameters:(NSDictionary *)queryDictionary
            {
                NSMutableArray *mutablePairs = [NSMutableArray array];
                for (NSString *key in queryDictionary) {
                    [mutablePairs addObject:[NSString stringWithFormat:@"%@=%@", CTPercentEscapedQueryStringKeyFromStringWithEncoding(key, NSUTF8StringEncoding), CTPercentEscapedQueryStringValueFromStringWithEncoding(queryDictionary[key], NSUTF8StringEncoding)]];
                }
            
                return [[NSString alloc]initWithFormat:@"%@?%@",url,[mutablePairs componentsJoinedByString:@"&"]];
            }
            
            static NSString * const kCharactersToBeEscapedInQueryString = @":/?&=;+!@#$()',*";
            
            static NSString * CTPercentEscapedQueryStringKeyFromStringWithEncoding(NSString *string, NSStringEncoding encoding) {
                static NSString * const kCharactersToLeaveUnescapedInQueryStringPairKey = @"[].";
            
                return (__bridge_transfer  NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)string, (__bridge CFStringRef)kCharactersToLeaveUnescapedInQueryStringPairKey, (__bridge CFStringRef)kCharactersToBeEscapedInQueryString, CFStringConvertNSStringEncodingToEncoding(encoding));
            }
            
            static NSString * CTPercentEscapedQueryStringValueFromStringWithEncoding(NSString *string, NSStringEncoding encoding) {
                return (__bridge_transfer  NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)string, NULL, (__bridge CFStringRef)kCharactersToBeEscapedInQueryString, CFStringConvertNSStringEncodingToEncoding(encoding));
            }
            

            并在您的代码中用作

            NSMutableDictionary *params = [[NSMutableDictionary alloc]init];
            [params setObject:@"2009-05-04T11:22:00+01:00" forKey:@"timestamp"];
            
            NSString *urlString = [self getParameterizedUrl:@"http://www.example.com" withParameters:params];
            NSURL *url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2010-10-25
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-09-30
              • 2018-06-21
              • 2018-03-02
              相关资源
              最近更新 更多