Al crear una GETsolicitud, no hay cuerpo para la solicitud, sino que todo va en la URL. Para crear una URL (y el porcentaje adecuado de escape), también puede usar URLComponents.
var url = URLComponents(string: "https://www.google.com/search/")!
url.queryItems = [
URLQueryItem(name: "q", value: "War & Peace")
]
El único truco es que la mayoría de los servicios web necesitan un +porcentaje de caracteres de escape (porque lo interpretarán como un carácter de espacio según lo dicta la application/x-www-form-urlencodedespecificación ). Pero URLComponentsno escapará por ciento. Apple sostiene que +es un carácter válido en una consulta y, por lo tanto, no debe escaparse. Técnicamente, tienen razón, que está permitido en una consulta de un URI, pero tiene un significado especial en las application/x-www-form-urlencodedsolicitudes y realmente no debe pasarse sin escape.
Apple reconoce que tenemos que escapar por ciento de los +personajes, pero aconseja que lo hagamos manualmente:
var url = URLComponents(string: "https://www.wolframalpha.com/input/")!
url.queryItems = [
URLQueryItem(name: "i", value: "1+2")
]
url.percentEncodedQuery = url.percentEncodedQuery?.replacingOccurrences(of: "+", with: "%2B")
Esta es una solución temporal poco elegante, pero funciona, y es lo que Apple aconseja si sus consultas pueden incluir un +carácter y tiene un servidor que las interpreta como espacios.
Entonces, combinando eso con tu sendRequestrutina, terminas con algo como:
func sendRequest(_ url: String, parameters: [String: String], completion: @escaping ([String: Any]?, Error?) -> Void) {
var components = URLComponents(string: url)!
components.queryItems = parameters.map { (key, value) in
URLQueryItem(name: key, value: value)
}
components.percentEncodedQuery = components.percentEncodedQuery?.replacingOccurrences(of: "+", with: "%2B")
let request = URLRequest(url: components.url!)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data,
let response = response as? HTTPURLResponse,
(200 ..< 300) ~= response.statusCode,
error == nil else {
completion(nil, error)
return
}
let responseObject = (try? JSONSerialization.jsonObject(with: data)) as? [String: Any]
completion(responseObject, nil)
}
task.resume()
}
Y lo llamarías así:
sendRequest("someurl", parameters: ["foo": "bar"]) { responseObject, error in
guard let responseObject = responseObject, error == nil else {
print(error ?? "Unknown error")
return
}
}
Personalmente, usaría JSONDecoderhoy en día y devolvería structun diccionario personalizado en lugar de un diccionario, pero eso no es realmente relevante aquí. Con suerte, esto ilustra la idea básica de cómo codificar porcentualmente los parámetros en la URL de una solicitud GET.
Consulte la revisión anterior de esta respuesta para Swift 2 y versiones de escape de porcentaje manual.
extension stringestá haciendo con los valores. Además, ¿cuándo debería usarloHttpBodyentonces?&separa un parámetro del siguiente, por lo que si&aparece en valor, no puede dejarlo sin escape). Con respectoHTTPBody, debe no utilizarlo enGETla solicitud; Se usa enPOSTpero noGET.NSMutableURLRequest, señalando que hay más de lo que sugiere el OP.NSJSONSerialization.dataWithJSONObject(parameters, options: nil, error: nil)?parameterssiendo una variedad de diccionarios[String: String]Use NSURLComponents para construir su NSURL de esta manera
var urlComponents = NSURLComponents(string: "https://www.google.de/maps/")! urlComponents.queryItems = [ NSURLQueryItem(name: "q", value: String(51.500833)+","+String(-0.141944)), NSURLQueryItem(name: "z", value: String(6)) ] urlComponents.URL // returns https://www.google.de/maps/?q=51.500833,-0.141944&z=6fuente
Estoy usando esto, pruébalo en el patio de recreo. Definir las URL base como estructura en constantes
struct Constants { struct APIDetails { static let APIScheme = "https" static let APIHost = "restcountries.eu" static let APIPath = "/rest/v1/alpha/" } } private func createURLFromParameters(parameters: [String:Any], pathparam: String?) -> URL { var components = URLComponents() components.scheme = Constants.APIDetails.APIScheme components.host = Constants.APIDetails.APIHost components.path = Constants.APIDetails.APIPath if let paramPath = pathparam { components.path = Constants.APIDetails.APIPath + "\(paramPath)" } if !parameters.isEmpty { components.queryItems = [URLQueryItem]() for (key, value) in parameters { let queryItem = URLQueryItem(name: key, value: "\(value)") components.queryItems!.append(queryItem) } } return components.url! } let url = createURLFromParameters(parameters: ["fullText" : "true"], pathparam: "IN") //Result url= https://restcountries.eu/rest/v1/alpha/IN?fullText=truefuente
Swift 3 :
extension URL { func getQueryItemValueForKey(key: String) -> String? { guard let components = NSURLComponents(url: self, resolvingAgainstBaseURL: false) else { return nil } guard let queryItems = components.queryItems else { return nil } return queryItems.filter { $0.name.lowercased() == key.lowercased() }.first?.value } }Lo usé para obtener el nombre de la imagen
UIImagePickerControllerenfunc imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]):var originalFilename = "" if let url = info[UIImagePickerControllerReferenceURL] as? URL, let imageIdentifier = url.getQueryItemValueForKey(key: "id") { originalFilename = imageIdentifier + ".png" print("file name : \(originalFilename)") }fuente
Puede extender su
Dictionarypara proporcionar solostringFromHttpParametersi tanto la clave como el valor se ajustan aCustomStringConvertableestoextension Dictionary where Key : CustomStringConvertible, Value : CustomStringConvertible { func stringFromHttpParameters() -> String { var parametersString = "" for (key, value) in self { parametersString += key.description + "=" + value.description + "&" } return parametersString } }esto es mucho más limpio y evita llamadas accidentales a
stringFromHttpParametersdiccionarios que no tienen negocios llamando a ese métodofuente
Esta extensión que sugirió @Rob funciona para Swift 3.0.1
No pude compilar la versión que incluyó en su publicación con Xcode 8.1 (8B62)
extension Dictionary { /// Build string representation of HTTP parameter dictionary of keys and objects /// /// :returns: String representation in the form of key1=value1&key2=value2 where the keys and values are percent escaped func stringFromHttpParameters() -> String { var parametersString = "" for (key, value) in self { if let key = key as? String, let value = value as? String { parametersString = parametersString + key + "=" + value + "&" } } parametersString = parametersString.substring(to: parametersString.index(before: parametersString.endIndex)) return parametersString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)! } }fuente
Yo suelo:
let dictionary = ["method":"login_user", "cel":mobile.text! "password":password.text!] as Dictionary<String,String> for (key, value) in dictionary { data=data+"&"+key+"="+value } request.HTTPBody = data.dataUsingEncoding(NSUTF8StringEncoding);fuente