Как закодировать + в% 2B с помощью NSURLComponents
Я использую 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")
Failed!
Выход равен:
http://www.example.com?connectionToken=abc+def
НЕ
http://www.example.com?connectionToken=abc%2Bdef
Я пробовал несколько вариантов, и я просто не могу заставить его выводить %2B
вообще.
Ответы
Ответ 1
Мой ответ от Radar 24076063 с объяснением, почему он работает так, как он делает (с небольшой очисткой текста):
Символ "+" является законным в компоненте запроса, поэтому он не должен быть закодирован в процентах.
Некоторые системы используют "+" в качестве пробела и требуют "+" символа "плюс" для процентного кодирования. Однако такое двухэтапное кодирование (преобразование знака плюс в% 2B, а затем преобразование пробела в знак плюса) подвержено ошибкам, поскольку оно легко приводит к проблемам с кодированием. Он также ломается, если URL-адрес нормализуется (синтаксическая нормализация URL-адресов включает удаление всего ненужного процентного кодирования — см. Раздел 6.2.2.2 rfc3986).
Итак, если вам нужно это поведение из-за сервера, с которым работает ваш код, вы сами будете обрабатывать дополнительные преобразования. Вот фрагмент кода, который показывает, что вам нужно делать в обоих направлениях:
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 +}"
)
Ответ 2
Как упоминают другие ответы, "+" по умолчанию не кодируется в iOS. Но если ваш сервер требует, чтобы он был закодирован, вот как это сделать:
var comps = URLComponents(url: self, resolvingAgainstBaseURL: true)
comps?.queryItems = [URLQueryItem(name: "name", value: "abc+def")]
comps?.percentEncodedQuery = comps?.percentEncodedQuery?.replacingOccurrences(of: "+", with: "%2B")
Ответ 3
+
может быть допустимым символом, когда тип содержимого - application/x-www-form-urlencoded, см. ссылку, поэтому NSURLComponents
doesn 't закодировать его.
Apple также упоминает this:
RFC 3986 указывает, какие символы должны быть закодированы в процентах в компонент запроса URL-адреса, но не как эти символы должны быть интерпретированы. Использование разделительных пар ключ-значение является общим конвенция, но не стандартизирована спецификацией. Поэтому вы могут столкнуться с проблемами совместимости с другими реализациями которые следуют этому соглашению.
Одним из примечательных примеров потенциальных проблем взаимодействия является то, как плюс знак (+) обрабатывается:
Согласно RFC 3986 знак плюса является допустимым символом в пределах запрос, и не обязательно должен быть закодирован в процентах. Однако, согласно рекомендации W3C для адресации URI, знак плюса зарезервирован как сокращенное обозначение для пространства внутри строки запроса (например,? Приветствие = привет + мир).
Если компонент запроса URL содержит дату, отформатированную в соответствии с RFC 3339 со знаком "плюс" в смещении временной области (например, 2013-12-31T14: 00: 00 + 00: 00), интерпретируя знак плюса как пробел приводит к недопустимому формату времени. RFC 3339 определяет, как быть отформатированным, но не сообщается, должен ли знак плюса быть % -кодировано в URL-адресе. В зависимости от получаемой реализации этот URL-адрес, вам может потребоваться упреждающий процент-кодировать знак плюса характер.
В качестве альтернативы рассмотрим комплекс кодирования и/или потенциально проблематичные данные в более надежном формате обмена данными, например JSON или XML.
В заключение вы можете или не можете кодировать "+".
По-моему, NSURLComponents
кодирует только символ, который должен быть закодирован, например, '&', '=' или китайские символы, такие как '你' '好', он не кодирует символ может кодироваться или не соответствовать типу содержимого, например, "+", упомянутому выше. Поэтому, если вы обнаружите, что вам нужно кодировать "+", или ваш сервер не может правильно разобрать, вы можете использовать код ниже.
Я не знаю, быстро, поэтому я просто предоставляю код objective-c, извините за это.
- (NSString *)URLEncodingValue:(NSString *)value
{
NSCharacterSet *set = [NSCharacterSet URLQueryAllowedCharacterSet];
NSMutableCharacterSet *mutableQueryAllowedCharacterSet = [set mutableCopy];
[mutableQueryAllowedCharacterSet removeCharactersInString:@"!*'();:@&=+$,/?%#[]"];
return [value stringByAddingPercentEncodingWithAllowedCharacters:mutableQueryAllowedCharacterSet];
}
! * '();: @& = + $,/?% # [] - зарезервированные символы, определенные в RFC 3986, код будет кодировать все они появляются в параметре значения, если вы просто хотите кодировать "+", просто замените !*'();:@&=+$,/?%#[]
на +
.
Ответ 4
Это ошибка Apple. Вместо этого используйте
NSString -stringByAddingPercentEncodingWithAllowedCharacters:
с
NSCharacterSet +URLQueryAllowedCharacterSet