Solicitud Swift GET con parámetros

Soy muy nuevo en cuanto a velocidad, así que probablemente tenga muchas fallas en mi código, pero lo que estoy tratando de lograr es enviar una solicitud GET a un servidor localhost con parámetros. Más, así que estoy tratando de lograrlo, dado que mi función toma dos parámetros baseURL:string,params:NSDictionary . No estoy seguro de cómo combinar esos dos en la URLRequest real? Esto es lo que he intentado hasta ahora

  func sendRequest(url:String,params:NSDictionary){ let urls: NSURL! = NSURL(string:url) var request = NSMutableURLRequest(URL:urls) request.HTTPMethod = "GET" var data:NSData! = NSKeyedArchiver.archivedDataWithRootObject(params) request.HTTPBody = data println(request) var session = NSURLSession.sharedSession() var task = session.dataTaskWithRequest(request, completionHandler:loadedData) task.resume() } } func loadedData(data:NSData!,response:NSURLResponse!,err:NSError!){ if(err != nil){ println(err?.description) }else{ var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary println(jsonResult) } } 

Al crear una solicitud GET , no hay un cuerpo para la solicitud, sino que todo va en la URL. Para construir una URL (y el porcentaje de URLComponents ), 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 + porcentaje de caracteres escapado (porque lo interpretarán como un carácter de espacio según lo dictado por la application/x-www-form-urlencoded specification ). Pero los URLComponents no escaparán por ciento. Apple sostiene que + es un carácter válido en una consulta y, por lo tanto, no se debe escapar. Técnicamente, son correctos, está permitido en una consulta de un URI, pero tiene un significado especial en application/x-www-form-urlencoded requests y realmente no se debe pasar sin guardar.

Apple reconoce que tenemos que escapar por ciento de los caracteres + , pero aconseja que lo hagamos manualmente:

 var url = URLComponents(string: "https://www.wolftwiglpha.com/input/")! url.queryItems = [ URLQueryItem(name: "i", value: "1+2") ] url.percentEncodedQuery = url.percentEncodedQuery?.replacingOccurrences(of: "+", with: "%2B") 

Este es un trabajo poco elegante, pero funciona, y es lo que Apple aconseja si sus consultas pueden incluir un carácter + y usted tiene un servidor que las interpreta como espacios.

Entonces, combinando eso con tu rutina sendRequest , 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, // is there data let response = response as? HTTPURLResponse, // is there HTTP response (200 ..< 300) ~= response.statusCode, // is statusCode 2XX error == nil else { // was there no error, otherwise ... 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 } // use `responseObject` here } 

Personalmente, usaría JSONDecoder hoy en día y devolvería una struct personalizada en lugar de un diccionario, pero eso no es realmente relevante aquí. Esperemos que esto ilustre 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 el porcentaje de escapes manual.

Use NSURLComponents para construir su NSURL como este

 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=6 

fuente: https://www.ralfebert.de/snippets/ios/encoding-nsurl-get-parameters/

Estoy usando esto, pruébalo en el patio de recreo. Defina las URL base como Struct 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=true 

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 para UIImagePickerController en func 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)") } 

Yo suelo:

 let dictionary = ["method":"login_user", "cel":mobile.text! "password":password.text!] as Dictionary for (key, value) in dictionary { data=data+"&"+key+"="+value } request.HTTPBody = data.dataUsingEncoding(NSUTF8StringEncoding); 

Esta extensión que @Rob sugirió que funciona para Swift 3.0.1

No pude comstackr 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)! } } 

Puede ampliar su Dictionary para que solo proporcione stringFromHttpParameter si tanto la clave como el valor se ajustan a CustomStringConvertable como este

 extension 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 stringFromHttpParameters en diccionarios que no tienen llamadas comerciales ese método