Objective-C和Swift中URL编码方法的不一致

时间:2017-06-06 03:48:03

标签: objective-c swift nsurl percent-encoding

我有以下Objective-C代码:

[@"http://www.google.com" stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLPathAllowedCharacterSet]];
// http%3A//www.google.com

然而,在斯威夫特:

"http://www.google.com".addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)
// http://www.google.com

我可以将这种差异归结为什么?

..并且为了额外的功劳,我可以依赖此代码来编码url路径保留字符,同时传递这样的完整网址吗?

1 个答案:

答案 0 :(得分:4)

问题实际上取决于NSString方法stringByAddingPercentEncodingWithAllowedCharactersString方法addingPercentEncoding(withAllowedCharacters:)之间的区别。而且这种行为已经从版本变为版本。 (看起来iOS 11的最新测试版现在恢复了我们以前看到的这种行为。)

我认为问题的根源在于路径百分比编码的细节。 RFC 3986的第3.3节说,除了相对路径的第一段之外,路径中允许使用冒号。

NSString方法捕获了这个概念,例如想象一个路径,其第一个目录是foo:(带冒号)和子目录bar:(也带冒号):

NSString *string = @"foo:/bar:";
NSCharacterSet *cs = [NSCharacterSet URLPathAllowedCharacterSet];
NSLog(@"%@", [string stringByAddingPercentEncodingWithAllowedCharacters:cs]);

结果是:

  

FOO%3A /栏:

页面第一部分中的:是百分比编码,但后续细分中的:不是。这捕获了如何在每RFC 3986的相对路径中处理冒号的逻辑。

String方法addingPercentEncoding(withAllowedCharacters:)不会这样做:

let string = "foo:/bar:"
os_log("%@", string.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!)

收率:

  

FOO:/栏:

显然,String方法不会尝试位置敏感逻辑。这个实现更符合方法的名称(它只考虑哪些字符是“允许的”,没有特殊的逻辑尝试猜测,根据允许的字符出现的位置,是否真正允许。)

我认为你背负了问题中提供的代码,但是我们应该注意到这种在相对路径中逃避冒号的行为,虽然有趣地解释了你的经历,但与你的直接问题并不真正相关。您提供的代码完全不正确。它试图对URL进行百分比编码,就像它只是一个路径一样。但是,这不是一条道路;它是一个URL,它与自己的规则不同。

对编码URL百分比的深入了解是要确认URL的不同组件允许不同的字符集,即它们需要不同的百分比编码。这就是NSCharacterSet有这么多不同的URL相关字符集的原因。

你真的应该对单个组件进行百分比编码,每个组件的百分比编码与该类型组件允许的字符集。只有当各个组件的编码百分比时,才应将它们连接在一起形成整个URL。

或者,NSURLComponents的设计正是为了达到这个目的,让您摆脱百分比的杂草 - 自己编码各个组件。例如:

var components = URLComponents(string: "http://httpbin.org/post")!
let foo = URLQueryItem(name: "foo", value: "bar & baz")
let qux = URLQueryItem(name: "qux", value: "42")
components.queryItems = [foo, qux]

let url = components.url!

这会产生以下结果,&和两个空格在foo值内正确转义百分比,但它正确地将&保留在foo之间qux

  

http://httpbin.org/post?foo=bar%20%26%20baz&qux=42

值得注意的是,NSURLComponents有一个小但却相当基本的缺陷:具体来说,如果您有查询值NSURLQueryItem,可能有+个字符,大多数网络服务需要转义百分比,但NSURLComponents不会。如果您的网址包含查询组件,并且这些查询值可能包含+个字符,我建议不要使用NSURLComponents,而是建议您自己对网址的各个组件进行百分比编码。