Search code examples
objective-cnsurl

iOS NSURL returning nil on valid URL


I've entered the URL http://localhost:8080/a?a=1\\tb?b=2 on the Safari it worked as expected but when using NSURL URLWithString it return nil. (The server also require \t character)

NSURL *url = [NSURL URLWithString:@"http://localhost:8080/a?a=1\\tb?b=2"];

Solution

  • The problem is that you need to percent-encode your values in the URL string. When it’s received by the server, it will decode this percent-encoded string in the URL into the desired value.

    But rather than percent-encoding yourself, you can use NSURLComponents. For example, if you want a to have the value of @"1\\tb", you can do:

    NSURLComponents *components = [NSURLComponents componentsWithString:@"http://localhost:8080"];
    components.queryItems = @[
        [NSURLQueryItem queryItemWithName:@"a" value:@"1\\tb"],
        [NSURLQueryItem queryItemWithName:@"b" value:@"2"]
    ];
    NSURL *url = components.URL;
    

    Yielding:

    http://localhost:8080?a=1%5Ctb&b=2
    

    Or, if you wanted it to have the tab character in the value associated with a (i.e. %09):

    NSURLComponents *components = [NSURLComponents componentsWithString:@"http://localhost:8080"];
    components.queryItems = @[
        [NSURLQueryItem queryItemWithName:@"a" value:@"1\tb"],
        [NSURLQueryItem queryItemWithName:@"b" value:@"2"]
    ];
    NSURL *url = components.URL;
    

    Yielding:

    http://localhost:8080?a=1%09b&b=2
    

    It just depends upon whether your server is expecting two characters, the \ followed by t (the first example) or the single \t character (the second example). Either way, the respective use of NSURLComponents will take care of the percent-encoding for you, and your server will decode it.


    For what it’s worth, the one caveat is the + character, which NSURLComponents won’t percent-encode for you (because, technically, a + character is allowed in a URL query). The problem is that the + character is interpreted as a space character by most web servers (per the x-www-form-urlencoded spec). If you need to pass a literal + character, you might want to replace those + characters, as advised by Apple:

    NSURLComponents *components = [NSURLComponents componentsWithString:@"http://localhost:8080"];
    components.queryItems = @[
        [NSURLQueryItem queryItemWithName:@"q" value:@"Romeo+Juliet"]
    ];
    components.percentEncodedQuery = [components.percentEncodedQuery stringByReplacingOccurrencesOfString:@"+" withString:@"%2B"];
    NSURL *url = components.URL;