Make an NSURL with an encoded plus (%2B)

妖精的绣舞 提交于 2019-12-04 18:09:46

问题


I need to pass a timestamp with a timezone offset in a GET request, e.g.,

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

This looks like a two arguments "2009-05-04T11:22:00" and "01:00" to the receiving PHP script (over which I've no control).

NSURL doesn't encode plus signs, but if I make an NSURL using the string

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

the url I end up with contains:

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

Any ideas how I can preserve my encoded plus sign or just plain prevent NSURL from encoding anything?


回答1:


What worked for me was doing the UTF8 conversion, then replacing the + sign with %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"];



回答2:


The string should be URL encoded.

Here is a category for NSString that will help:

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:


Use NSString's stringByAddingPercentEscapesUsingEncoding: method on the text you want to include as an argument.

As its name implies, the method will convert return an auto-released string containing an url-safe version of the receiver.




回答4:


Thought I may as well provide my workaround as an answer, as I don't think there's a good solution to the original problem.

The plus sign (+) is completely valid in a URL, so my solution was to convert the time to GMT and remove the timezone/DST offset from the string. I'll leave it as an exercise for the reader to determine the value of secondsFromGMT below as, in my case, it's always the same because I'm only interested in timestamps generated by a web server.

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



回答5:


encode you string by using below code

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

this will encode + of you string which will prevent replacement of + by %2b while posting data in post method




回答6:


To get encoded plus (%2B) (It works with all charcters) use 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));
}

And use in your code as

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



回答7:


Solution when using 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


来源:https://stackoverflow.com/questions/898488/make-an-nsurl-with-an-encoded-plus-2b

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!