我使用的是NSURLComponents,我似乎无法正确编码查询值。我需要最终网址将+
表示为%2B
。
let baseUrl = NSURL(string: "http://www.example.com")
let components = NSURLComponents(URL: baseUrl, resolvingAgainstBaseURL: true)
components.queryItems = [ NSURLQueryItem(name: "name", value: "abc+def") ]
XCTAssertEqual(components!.string!, "http://www.example.com?connectionToken=abc%2Bdef")
失败!
输出等于:
http://www.example.com?connectionToken=abc+def
不是
http://www.example.com?connectionToken=abc%2Bdef
我尝试过多种变体,而我似乎根本无法输出%2B
。
答案 0 :(得分:19)
我在Radar 24076063的回答中解释了为什么它的工作原理(通过一些文本的清理):
' +'字符在查询组件中是合法的,因此不需要进行百分比编码。
有些系统会使用' +'作为一个空间,需要' +'要加百分比编码的加号字符。但是,这种两阶段编码(将加号转换为%2B然后将空格转换为加号)容易出错,因为它很容易导致编码问题。如果URL被规范化,它也会中断(URL的语法规范化包括删除所有不必要的百分比编码 - 请参阅rfc3986第6.2.2.2节)。
因此,如果您因为代码正在与之交谈的服务器而需要这种行为,那么您将自己处理额外的转换。这是一段代码,显示了您需要做的两种方式:
NSURLComponents *components = [[NSURLComponents alloc] init]; NSArray *items = [NSArray arrayWithObjects:[NSURLQueryItem queryItemWithName:@"name" value:@"Value +"], nil]; components.queryItems = items; NSLog(@"URL queryItems: %@", [components queryItems]); NSLog(@"URL string before: %@", [components string]); // Replace all "+" in the percentEncodedQuery with "%2B" (a percent-encoded +) and then replace all "%20" (a percent-encoded space) with "+" components.percentEncodedQuery = [[components.percentEncodedQuery stringByReplacingOccurrencesOfString:@"+" withString:@"%2B"] stringByReplacingOccurrencesOfString:@"%20" withString:@"+"]; NSLog(@"URL string after: %@", [components string]); // This is the reverse if you receive a URL with a query in that form and want to parse it with queryItems components.percentEncodedQuery = [[components.percentEncodedQuery stringByReplacingOccurrencesOfString:@"+" withString:@"%20"] stringByReplacingOccurrencesOfString:@"%2B" withString:@"+"]; NSLog(@"URL string back: %@", [components string]); NSLog(@"URL queryItems: %@", [components queryItems]);
输出结果为:
URL queryItems: ( "<NSURLQueryItem 0x100502460> {name = name, value = Value +}" ) URL string before: ?name=Value%20+ URL string after: ?name=Value+%2B URL string back: ?name=Value%20+ URL queryItems: ( "<NSURLQueryItem 0x1002073e0> {name = name, value = Value +}" )
答案 1 :(得分:9)
正如其他答案所述,默认情况下,“+”未在iOS上编码。但是,如果您的服务器需要进行编码,请按以下步骤操作:
var comps = URLComponents(url: self, resolvingAgainstBaseURL: true)
// a local var is needed to fix a swift warning about "overlapping accesses" caused by writing to the same property that's being read.
var compsCopy = comps
compsCopy?.queryItems = [URLQueryItem(name: "name", value: "abc+def")]
comps?.percentEncodedQuery = compsCopy?.percentEncodedQuery?.replacingOccurrences(of: "+", with: "%2B")
答案 2 :(得分:4)
+
可能是有效字符,请参阅the link,因此NSURLComponents
不对其进行编码。
Apple还提到this:
RFC 3986指定哪些字符必须在其中进行百分比编码 查询URL的组件,但不是这些字符应该如何 解释。使用分隔的键值对是常见的 惯例,但没有规范标准化。所以,你 可能会遇到与其他实现的互操作性问题 遵循这一惯例。
潜在的互操作性问题的一个值得注意的例子是如何 处理加号(+)字符:
根据RFC 3986,加号是a中的有效字符 查询,并且不需要进行百分比编码。但是,根据 对于URI寻址的W3C建议,加号是保留的 作为查询字符串中空格的简写表示法(例如, ?问候=你好+世界)。
如果URL查询组件包含根据RFC格式化的日期 3339在时区偏移量中带加号(例如, 2013-12-31T14:00:00 + 00:00),将加号解释为空格 导致时间格式无效。 RFC 3339指定日期应该如何 格式化,但不建议加号是否必须 在URL中编码的百分比。取决于实施接收 在此URL中,您可能需要抢先对加号进行百分比编码 字符。
作为替代方案,请考虑编码复杂和/或潜在的编码 有问题的数据采用更强大的数据交换格式,例如 JSON或XML。
结论是,您可能编码也可能不编码&#39; +&#39;。
在我看来,NSURLComponents
只编码确保应编码的字符,例如&#39;&amp;&#39;,&#39; =&#39;或汉字,如&#39;你&#39; &#39;好&#39;,它不会根据内容类型编码或不编码字符,例如&#39; +&#39;我上面提到过。因此,如果您发现必须编码&#39; +&#39;或者您的服务器无法正确解析,您可以使用下面的代码。
我不太了解,所以我只提供了客观的代码,对不起。
- (NSString *)URLEncodingValue:(NSString *)value
{
NSCharacterSet *set = [NSCharacterSet URLQueryAllowedCharacterSet];
NSMutableCharacterSet *mutableQueryAllowedCharacterSet = [set mutableCopy];
[mutableQueryAllowedCharacterSet removeCharactersInString:@"!*'();:@&=+$,/?%#[]"];
return [value stringByAddingPercentEncodingWithAllowedCharacters:mutableQueryAllowedCharacterSet];
}
!*'();:@&=+$,/?%#[]是RFC 3986中定义的保留字符,代码将编码所有这些字符出现在value参数中,如果您只想编码&#39; +&#39;,只需替换{{1与!*'();:@&=+$,/?%#[]
。
答案 3 :(得分:1)
这是一个Apple bug。而是使用
NSString -stringByAddingPercentEncodingWithAllowedCharacters:
与
NSCharacterSet +URLQueryAllowedCharacterSet