Iphone 使用编码的加号(%2B)生成NSURL

Iphone 使用编码的加号(%2B)生成NSURL,iphone,url,html-encode,Iphone,Url,Html Encode,我需要在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 我最终使用的url包含: 2009-05-04T11:22:00%252B01:00 您知道如何保留已编码的加号,或者干脆阻止NSURL对任何内容进行编码吗?在要作为参数包含

我需要在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

我最终使用的url包含:

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


您知道如何保留已编码的加号,或者干脆阻止NSURL对任何内容进行编码吗?

在要作为参数包含的文本上添加PercenteScapesusingEncoding:方法,使用
NSString
string


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

认为我也可以提供我的解决方法作为答案,因为我认为没有很好的解决方案来解决原始问题

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

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

对我有效的方法是进行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"];

字符串应该是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));
}

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

NSString*result=(NSString*)CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)self,NULL,(CFStringRef)@“+”,kCFStringEncodingUTF8)

这将对字符串中的+进行编码,这将防止在post方法中发布数据时用%2b替换+以获得编码的加号(%2b)(它适用于所有字符)使用
CFURLCreateStringByAddingPercentEscapes

/**
 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]];

使用URL组件时的解决方案(Swift 3):


我试过了-它将“+”转换为“%2B”。NSURL然后对“%”进行编码,因此最终得到的结果是“%252B”。很可能是URL出了问题。您需要使用NSURL的
URLWithString:
。并确保不对同一个字符串调用该方法两次,否则它将调用该方法并对结果字符串进行两次编码,从而将%编码为%25。还要确保你在任何地方都使用了NSUTF8编码。它就是不起作用。“+”字符在URL中完全有效,不会被NSURL编码。如果您将其保留在中,它将显示为单独的参数。最后,我不得不将时间戳转换为GMT,并从字符串中删除时区偏移量。不太好,但还有其他问题需要解决…我不明白这是怎么一个正确的答案。这些问题询问如何创建适当的NSURL对象。如果此字符串用于创建NSURL对象,则%符号将再次编码为%25。请澄清。这解决了问题。但是,这不是正确的解决方案,因为它只处理“+”而不处理其他需要编码的字符。这对我不起作用。相反,在创建URL字符串之前,我使用Ric Santos的答案对时间戳进行了编码。根据我的经验,我从未见过有人需要对url的参数名、模式、域或其他部分进行编码。因此,最好将参数值单独编码。但是,如果有一个函数能够将一个url分解,正确编码,然后将其重新组合在一起,那就太好了。我假设StringByAddingPercentescapesusingEncode可以做到这一点,但显然对于+符号这样的情况它失败了。
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