Pase el parámetro en WebService en Swift

Estoy aprendiendo Swift y no sé cómo enviar parámetros al servidor usando Swift. En Objective-C podemos hacer esto usando "%@" como marcador de posición. Pero, ¿qué debería hacerse en el caso de Swift? Supongamos que tengo un servicio web de inicio de sesión que requiere un correo electrónico y una contraseña.

Ahora quiero saber es cómo voy a enviar el campo logintextfield y passwordtextfield al servidor, como,

 var bodyData = "email=logintextfield.text&password=passwordtextfield.text" 

Al crear una solicitud HTTP que incluye la entrada del usuario, generalmente se debe escapar en un porcentaje en caso de que haya caracteres reservados en la entrada del usuario, por lo tanto:

 let login = logintextfield.text?.addingPercentEncodingForURLQueryValue() ?? "" let password = passwordtextfield.text?.addingPercentEncodingForURLQueryValue() ?? "" let bodyData = "email=\(login)&password=\(password)" 

Tenga en cuenta que realmente desea verificar si el login y la password son nil o no. De todos modos, el porcentaje de escape se hace de la siguiente manera:

 extension String { /// Percent escapes values to be added to a URL query as specified in RFC 3986 /// /// This percent-escapes all characters besides the alphanumeric character set and "-", ".", "_", and "~". /// /// http://www.ietf.org/rfc/rfc3986.txt /// /// :returns: Returns percent-escaped string. func addingPercentEncodingForURLQueryValue() -> String? { let allowedCharacters = CharacterSet(charactersIn: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~") return self.addingPercentEncoding(withAllowedCharacters: allowedCharacters) } } 

Vea esta respuesta para otra versión de esta extensión.


Si desea ver una demostración del uso de lo anterior, imagine la siguiente solicitud:

 let keyData = "AIzaSyCRLa4LQZWNQBcjCYcIVYA45i9i8zfClqc" let sensorInformation = false let types = "building" let radius = 1000000 let locationCoordinate = CLLocationCoordinate2D(latitude:40.748716, longitude: -73.985643) let name = "Empire State Building, New York, NY" let floors = 102 let now = Date() let params:[String: Any] = [ "key" : keyData, "sensor" : sensorInformation, "typesData" : types, "radius" : radius, "location" : locationCoordinate, "name" : name, "floors" : floors, "when" : now, "pi" : M_PI] let url = URL(string: "http://some.web.site.com/inquiry")! var request = URLRequest(url: url) request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") request.httpBody = params.dataFromHttpParameters() let task = URLSession.shared.dataTask(with: request) { data, response, error in guard data != nil && error == nil else { print("error submitting request: \(error)") return } if let httpResponse = response as? HTTPURLResponse where httpResponse.statusCode != 200 { print("response was not 200: \(response)") return } // handle the data of the successful response here } task.resume() 

Incluyo muchos parámetros que no se incluyeron en su ejemplo, sino simplemente como una forma de ilustrar el manejo rutinario de una gran variedad de tipos de parámetros.

Por cierto, lo anterior usa mis datafromHttpParameters función datafromHttpParameters :

 extension Dictionary { /// This creates a String representation of the supplied value. /// /// This converts NSDate objects to a RFC3339 formatted string, booleans to "true" or "false", /// and otherwise returns the default string representation. /// /// - parameter value: The value to be converted to a string /// /// - returns: String representation private func httpStringRepresentation(_ value: Any) -> String { switch value { case let date as Date: return date.rfc3339String() case let coordinate as CLLocationCoordinate2D: return "\(coordinate.latitude),\(coordinate.longitude)" case let boolean as Bool: return boolean ? "true" : "false" default: return "\(value)" } } /// Build `Data` representation of HTTP parameter dictionary of keys and objects /// /// This percent escapes in compliance with RFC 3986 /// /// http://www.ietf.org/rfc/rfc3986.txt /// /// :returns: String representation in the form of key1=value1&key2=value2 where the keys and values are percent escaped func dataFromHttpParameters() -> Data { let parameterArray = self.map { (key, value) -> String in let percentEscapedKey = (key as! String).addingPercentEncodingForURLQueryValue()! let percentEscapedValue = httpStringRepresentation(value).addingPercentEncodingForURLQueryValue()! return "\(percentEscapedKey)=\(percentEscapedValue)" } return parameterArray.joined(separator: "&").data(using: .utf8)! } } 

Aquí, como estoy tratando con una matriz de cadenas de parámetros, utilizo la función de join para concatenarlas separadas por & , pero la idea es la misma.

Siéntase libre de personalizar esa función para manejar cualquier tipo de datos que pueda estar pasando (por ejemplo, generalmente no tengo CLLocationCoordinate2D allí, pero su ejemplo incluía uno, así que quería mostrar cómo se vería). Pero la clave es que si está suministrando cualquier campo que incluya la entrada del usuario, asegúrese de escapar por ciento.

FYI, esta es mi función rfc3339String que se usa arriba. (Claramente, si no necesita transmitir fechas, no necesita esto, pero lo estoy incluyendo en aras de la exhaustividad para una solución más general).

 extension Date { /// Get RFC 3339/ISO 8601 string representation of the date. /// /// For more information, see: /// /// https://developer.apple.com/library/ios/qa/qa1480/_index.html /// /// - returns: Return RFC 3339 representation of date string func rfc3339String() -> String { let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSX" formatter.timeZone = TimeZone(secondsFromGMT: 0) formatter.locale = Locale(identifier: "en_US_POSIX") return formatter.string(from: self) } } 

Para ver la representación de Swift 2, consulte la versión anterior de esta respuesta.

Se puede hacer pasando el parámetro requerido en el servicio de esta manera,

 var urlPath = NSString(format: "https://maps.googleapis.com/maps/api/place/search/json?key=AIzaSyCRLa4LQZWNQBcjCYcIVYA45i9i8zfClqc&sensor=false&types=restaurant&radius=100000&location=\(locationCoord)") 

Aquí urlPath es el servicio web que contiene url y locationCoord (como último parámetro) es el valor de tiempo de ejecución para el parámetro de ubicación para el servicio web. La clave de parámetro, sensor, radio y tipos son fijos.

Llamaré a json al hacer clic en el botón de inicio de sesión

 @IBAction func loginClicked(sender : AnyObject){ var request = NSMutableURLRequest(URL: NSURL(string: kLoginURL)) // Here, kLogin contains the Login API. var session = NSURLSession.sharedSession() request.HTTPMethod = "POST" var err: NSError? request.HTTPBody = NSJSONSerialization.dataWithJSONObject(self.criteriaDic(), options: nil, error: &err) // This Line fills the web service with required parameters. request.addValue("application/json", forHTTPHeaderField: "Content-Type") request.addValue("application/json", forHTTPHeaderField: "Accept") var task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in // println("Response: \(response)") var strData = NSString(data: data, encoding: NSUTF8StringEncoding) println("Body: \(strData)") var err1: NSError? var json2 = NSJSONSerialization.JSONObjectWithData(strData.dataUsingEncoding(NSUTF8StringEncoding), options: .MutableLeaves, error:&err1 ) as NSDictionary println("json2 :\(json2)") if(err) { println(err!.localizedDescription) } else { var success = json2["success"] as? Int println("Succes: \(success)") } }) task.resume() } 

Aquí, he hecho un diccionario separado para los parámetros.

 var params = ["format":"json", "MobileType":"IOS","MIN":"f8d16d98ad12acdbbe1de647414495ec","UserName":emailTxtField.text,"PWD":passwordTxtField.text,"SigninVia":"SH"]as NSDictionary return params } 

En base a lo anterior, terminé con esto, para obtener un token dentro de un elemento Set-Cookie.

Donde el URLResponse era

  { URL: http://bla.co.uk//auth/authenticate?email=bob@isp.eu&password=xcode } { status code: 200, headers { "Cache-Control" = "private, must-revalidate"; Connection = "keep-alive"; "Content-Type" = "application/json"; Date = "Fri, 17 Feb 2017 10:51:41 GMT"; Expires = "-1"; Pragma = "no-cache"; Server = nginx; "Set-Cookie" = "token=Cu4CmOaverylongstring0mCu4CmOpBGg; expires=Fri, 17-Feb-2017 20:51:41 GMT; Max-Age=36000; path=auth; httponly"; "Transfer-Encoding" = Identity; "X-Powered-By" = "PHP/5.5.9-1ubuntu4.19, PleskLin"; } } func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) { let httpResponse = response as! HTTPURLResponse let statusCode = httpResponse.statusCode if statusCode == 200 { let keyValues = httpResponse.allHeaderFields.map { (String(describing: $0.key).lowercased(), String(describing: $0.value)) } // Now filter the array, searching for your header-key, also lowercased if let myHeaderValue = keyValues.filter({ $0.0 == "Set-Cookie".lowercased() }).first { print(myHeaderValue.1) let cookies = myHeaderValue.1 let cookieDict = cookies.components(separatedBy: ";") print("\(cookieDict)") let tokenEntryParameter = cookieDict.filter({$0 .contains("token")}) let tokenEntry = tokenEntryParameter.first token = (tokenEntry?.components(separatedBy: "=").last)! } } }