Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 如何编码+;使用NSURL组件转换为%2B_Swift_Encoding_Nsurl_Url Encoding - Fatal编程技术网

Swift 如何编码+;使用NSURL组件转换为%2B

Swift 如何编码+;使用NSURL组件转换为%2B,swift,encoding,nsurl,url-encoding,Swift,Encoding,Nsurl,Url Encoding,我使用的是NSURLComponents,似乎无法正确编码查询值。我需要最后的URL将+表示为%2B let baseUrl = NSURL(string: "http://www.example.com") let components = NSURLComponents(URL: baseUrl, resolvingAgainstBaseURL: true) components.queryItems = [ NSURLQueryItem(name: "name", value: "

我使用的是NSURLComponents,似乎无法正确编码查询值。我需要最后的URL将
+
表示为
%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 
不是


我尝试了几种变体,但似乎根本无法将其输出到
%2B

这是一个苹果bug。改用

NSString -stringByAddingPercentEncodingWithAllowedCharacters:

我的回答是,解释了为什么它是这样工作的(稍微清理一下文本):

“+”字符在查询组件中是合法的,因此不需要对其进行百分比编码

某些系统使用“+”作为空格,并要求“+”加号进行百分比编码。然而,这种两阶段编码(将加号转换为%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 +}"
)
URL查询项:(
{name=name,value=value+}
)
URL字符串之前:?名称=值%20+
以下URL字符串:?名称=值+%2B
返回URL字符串:?名称=值%20+
URL查询项:(
{name=name,value=value+}
)

当内容类型为application/x-www-form-urlencoded时,
+
可能是有效字符,请参阅,因此
NSURLComponents
不会对其进行编码

苹果还提到:

RFC 3986指定哪些字符必须在 URL的查询组件,但不包括这些字符应如何显示 解释。使用分隔键-值对是一种常见的方法 约定,但未通过规范进行标准化。所以你 可能会遇到与其他实现的互操作性问题 按照这个惯例

潜在互操作性问题的一个显著例子是 处理加号(+)字符:

根据RFC 3986,加号是一个字符中的有效字符 查询,不需要进行百分比编码。但是根据 W3C关于URI寻址的建议中,加号是保留的 作为查询字符串中空格的简写符号(例如, 问候语=你好+世界)

如果URL查询组件包含根据RFC格式化的日期 3339,时区偏移中带有加号(例如, 2013-12-31T14:00:00+00:00),将加号解释为空格 导致时间格式无效。RFC 3339规定了日期的显示方式 已格式化,但不建议加号是否必须为 URL中编码的百分比。取决于接收的实施情况 对于此URL,您可能需要先对加号进行百分比编码 性格

作为一种选择,考虑复杂和/或潜在的编码。 问题数据采用更健壮的数据交换格式,如 JSON或XML

结论是您可以或不可以对“+”进行编码

在我看来,
NSURLComponents
只对它确保应该编码的字符进行编码,例如“&”、“=”或类似的中文字符你' '好', 它不编码字符可以根据内容类型编码或不编码,如上面提到的“+”。因此,如果您发现必须对“+”进行编码,或者您的服务器无法正确解析,您可以使用下面的代码

我不知道swift,所以我只提供objective-c代码,很抱歉

- (NSString *)URLEncodingValue:(NSString *)value
{
    NSCharacterSet *set = [NSCharacterSet URLQueryAllowedCharacterSet];
    NSMutableCharacterSet *mutableQueryAllowedCharacterSet = [set mutableCopy];
    [mutableQueryAllowedCharacterSet removeCharactersInString:@"!*'();:@&=+$,/?%#[]"];
    return [value stringByAddingPercentEncodingWithAllowedCharacters:mutableQueryAllowedCharacterSet];
}

是RFC 3986中定义的保留字符,代码将对所有这些字符进行编码并显示在value参数中,如果您只想编码“+”,只需替换
!*”();:@&=+$,/?%#[]
+

如其他答案所述,“+”默认情况下不会在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")

寓意:当添加没有可靠规范的API时,您必须对模糊部分做出决策,而这些决策不会适用于所有人。对于NSURLComponents.queryItems,我们决定遵循rfc3986/std66(URI标准),以确定名称和值字符串中哪些字符应该和不应该进行百分比编码。名称和值字符串中百分比编码的唯一有效查询组件字符是查询项分隔符“&”和“=”。如果您希望替换其他字符或百分比编码,这里的代码片段将显示如何完成。如果不清楚,Jim在上面的评论中的“我们”是指您购买计算机的公司的开发人员;)问题是,Oracle的Java URL编码使用/解释“+”编码。因为NSURLComponents不编码“+”符号,我们必须以不同的方式翻译“+”,这取决于URL是传出的还是正在构造的。如果NSURLComponents只是对“+”符号进行编码,那么兼容性问题将变得无关紧要-只要将“+”转换为%20,一切都会正常工作:-(事实上,这不是一个bug。规范(非常)模糊,几乎所有与HTTP相关的东西都是如此…
- (NSString *)URLEncodingValue:(NSString *)value
{
    NSCharacterSet *set = [NSCharacterSet URLQueryAllowedCharacterSet];
    NSMutableCharacterSet *mutableQueryAllowedCharacterSet = [set mutableCopy];
    [mutableQueryAllowedCharacterSet removeCharactersInString:@"!*'();:@&=+$,/?%#[]"];
    return [value stringByAddingPercentEncodingWithAllowedCharacters:mutableQueryAllowedCharacterSet];
}
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")