NSURL URLWithString:relativeToURL: is clipping rel

2019-02-05 18:07发布

I'm trying to implement an iOS app, which uses RestKit. In all examples I've seen so far the following code is used to create the URLs:

NSURL *baseURL = [NSURL URLWithString:@"https://api.service.com/v1"];
NSURL *relativeURL = [NSURL URLWithString:@"/files/search" relativeToURL:baseURL];

But then [relativeURL absoluteString] will return https://api.service.com/files/search.

So I tried a few examples:

NSURL *baseURL1 = [NSURL URLWithString:@"https://api.service.com/v1/"];
NSURL *baseURL2 = [NSURL URLWithString:@"https://api.service.com/v1"];
NSURL *baseURL3 = [NSURL URLWithString:@"/v1" relativeToURL:[NSURL URLWithString:@"https://api.service.com"]];

NSURL *relativeURL1 = [NSURL URLWithString:@"/files/search" relativeToURL:baseURL1];
NSURL *relativeURL2 = [NSURL URLWithString:@"/files/search" relativeToURL:baseURL2];
NSURL *relativeURL3 = [NSURL URLWithString:@"/files/search" relativeToURL:baseURL3];
NSURL *relativeURL4 = [NSURL URLWithString:@"files/search" relativeToURL:baseURL1];
NSURL *relativeURL5 = [NSURL URLWithString:@"files/search" relativeToURL:baseURL2];
NSURL *relativeURL6 = [NSURL URLWithString:@"files/search" relativeToURL:baseURL3];

NSLog(@"1: %@", [relativeURL1 absoluteString]);
NSLog(@"2: %@", [relativeURL2 absoluteString]);
NSLog(@"3: %@", [relativeURL3 absoluteString]);
NSLog(@"4: %@", [relativeURL4 absoluteString]);
NSLog(@"5: %@", [relativeURL5 absoluteString]);
NSLog(@"6: %@", [relativeURL6 absoluteString]);

And this is the output:

1: https://api.service.com/files/search
2: https://api.service.com/files/search
3: https://api.service.com/files/search
4: https://api.service.com/v1/files/search
5: https://api.service.com/files/search
6: https://api.service.com/files/search

So the only example returning what I want is #4. Can anyone explain why?

标签: ios url nsurl
3条回答
放荡不羁爱自由
2楼-- · 2019-02-05 18:13

I read [RFC1808] which defines the normative algorithm for resolving relative URLs

2 issues:

  1. the relative url may not start with a / or it is considered to be absolute:

    Step 4: If the embedded URL path is preceded by a slash "/", the
       path is not relative and we skip to Step 7."
    
  2. when the base url ends with a non-slash. everything from the last slash on is skipped

    Step 6: The last segment of the base URL's path (anything
       following the rightmost slash "/", or the entire path if no
       slash is present) is removed and the embedded URL's path is
       appended in its place.  The following operations are
       then applied, in order, to the new path:"
    

so that explains it. the baseURL needs to end in a / and the relative url shouldn't start with a /

查看更多
Ridiculous、
3楼-- · 2019-02-05 18:25

You have two problems here:

Firstly, the string /files/search is an absolute path since it starts with a slash. Resolving it against any existing URL will ignore the existing path.

Secondly, https://api.service.com/v1 does not have a trailing slash to indicate it's a directory. Any strings resolved against it will always ignore the v1 portion.

To conclude, you need that combo of a relative path — files/search — and directory base URL — https://api.service.com/v1/.

查看更多
贼婆χ
4楼-- · 2019-02-05 18:33

Another example:

//it's right
NSURL *url = [NSURL URLWithString:@"getValidNumber" relativeToURL:[NSURL URLWithString:@"http://dns.test.com:22009/service/"]]; 

//error
NSURL *url = [NSURL URLWithString:@"getValidNumber" relativeToURL:[NSURL URLWithString:@"dns.test.com:22009/service/"]]; 

//error
NSURL *url = [NSURL URLWithString:@"/getValidNumber" relativeToURL:[NSURL URLWithString:@"http://dns.test.com:22009/service"]];

` The 'http://' is necessary to use this method.

查看更多
登录 后发表回答