Подтвердить что ты не робот

Как закодировать + в% 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 вообще.

4b9b3361

Ответ 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