swift encoding nsurl url-encoding

swift - Cómo codificar+en% 2B con NSURLComponents



encoding url-encoding (4)

Estoy usando NSURLComponents y parece que no puedo obtener los valores de consulta para codificar correctamente. Necesito la URL final para representar a + como %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")

¡Ha fallado!

La salida es igual a:

http://www.example.com?connectionToken=abc+def

NO

http://www.example.com?connectionToken=abc%2Bdef

Probé varias variaciones y parece que no puedo obtener la salida %2B .


Este es un error de Apple. En su lugar use

NSString -stringByAddingPercentEncodingWithAllowedCharacters:

con

NSCharacterSet +URLQueryAllowedCharacterSet


Mi respuesta de Radar 24076063 con una explicación de por qué funciona de la forma en que funciona (con un poco de limpieza del texto):

El carácter ''+'' es legal en el componente de consulta, por lo que no es necesario que esté codificado en porcentajes.

Algunos sistemas usan el ''+'' como un espacio y requieren que ''+'' el carácter más esté codificado en porcentajes. Sin embargo, ese tipo de codificación de dos etapas (convirtiendo el signo más en% 2B y luego convirtiendo el espacio en signo más) es propenso a errores porque conduce fácilmente a problemas de codificación. También se rompe si la URL se normaliza (la normalización de sintaxis de las URL incluye la eliminación de toda la codificación porcentual innecesaria; consulte la sección 6.2.2.2 de rfc3986).

Entonces, si necesita ese comportamiento debido al servidor con el que está hablando su código, usted mismo se encargará de la (s) transformación (es) adicional (es). Aquí hay un fragmento de código que muestra lo que debe hacer en ambos sentidos:

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]);

El resultado es:

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 +}" )


+ puede ser un carácter válido cuando el tipo de contenido es application / x-www-form-urlencoded, ver el enlace , por lo que NSURLComponents no lo codifica.

Apple también menciona esto :

RFC 3986 especifica qué caracteres deben estar codificados porcentualmente en el componente de consulta de una URL, pero no cómo deben interpretarse esos caracteres. El uso de pares clave-valor delimitados es una convención común, pero no está estandarizada por una especificación. Por lo tanto, puede encontrar problemas de interoperabilidad con otras implementaciones que siguen esta convención.

Un ejemplo notable de posibles problemas de interoperabilidad es cómo se maneja el carácter del signo más (+):

De acuerdo con RFC 3986, el signo más es un carácter válido dentro de una consulta, y no necesita ser codificado por porcentaje. Sin embargo, de acuerdo con las recomendaciones W3C para el direccionamiento de URI, el signo más se reserva como notación abreviada para un espacio dentro de una cadena de consulta (por ejemplo,? Greeting = hello + world).

Si un componente de consulta URL contiene una fecha formateada de acuerdo con RFC 3339 con un signo más en el desplazamiento de la zona horaria (por ejemplo, 2013-12-31T14: 00: 00 + 00: 00), interpretar el signo más como un espacio da como resultado un formato de tiempo no válido. RFC 3339 especifica cómo deben formatearse las fechas, pero no aconseja si el signo más debe estar codificado en porcentajes en una URL. Según la implementación que reciba esta URL, es posible que deba codificar porcentualmente de forma preventiva el carácter de signo más.

Como alternativa, considere codificar datos complejos y / o potencialmente problemáticos en un formato de intercambio de datos más sólido, como JSON o XML.

La conclusión es que puede o no codificar ''+''.

En mi opinión, los NSURLComponents solo codifican caracteres que se aseguran de que se deben codificar, como ''&'', ''='' o caracteres chinos como ''你'' ''好'', no codifica que el carácter se pueda codificar o no de acuerdo al tipo de contenido, como ''+'' que mencioné anteriormente. Entonces, si encuentra que tiene que codificar ''+'' o su servidor no puede analizar correctamente, puede usar el siguiente código.

No sé rápido, así que solo proporciono el código objetivo-c, lo siento por eso.

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

! * ''();: @ & = + $, /?% # [] son caracteres reservados definidos en RFC 3986, el código codificará todos ellos aparecen en el parámetro de valor, si solo desea codificar'' + '', simplemente reemplace !*''();:@&=+$,/?%#[] con + .


Como las otras respuestas mencionan, "+" no está codificado en iOS por defecto. Pero si su servidor requiere que se codifique, esta es la forma de hacerlo:

var comps = URLComponents(url: self, resolvingAgainstBaseURL: true) comps?.queryItems = [URLQueryItem(name: "name", value: "abc+def")] comps?.percentEncodedQuery = comps?.percentEncodedQuery?.replacingOccurrences(of: "+", with: "%2B")