在Swift中传递WebService中的参数

我正在学习Swift,我不知道如何使用Swift将参数发送到服务器。 在Objective-C中,我们可以使用"%@"作为占位符。 但是,Swift的情况下应该怎么做,假设我有一个需要电子邮件和密码的loginWeb服务。

现在我想知道的是,我将如何发送logintextfieldpasswordtextfield文本到服务器,如,

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

在创build包含用户input的HTTP请求时,如果用户input中有任何保留字符,通常应该百分比转义,因此:

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

请注意,你真的要检查,看看loginpassword是否nil 。 无论如何,百分比转义完成如下:

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

请参阅此答案以获取此扩展程序的另一个版本。


如果你想看到使用上面的演示,想象下面的请求:

 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() 

我包含了许多参数,这些参数并没有包括在你的例子中,而仅仅是作为一种说明例程处理各种参数types的方法。

顺便说一下,以上使用我的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)! } } 

在这里,因为我正在处理一个参数string数组,所以我使用join函数连接它们,并用&分开,但这个想法是一样的。

随意定制这个函数来处理你可能传入的任何数据types(例如我通常没有CLLocationCoordinate2D ,但是你的例子包含了一个,所以我想展示它的样子)。 但关键是,如果您提供包含用户input的任何字段,请确保以百分比转义。

仅供参考,这是我上面使用的rfc3339String函数。 (显然,如果你不需要传输date,你不需要这个,但是为了更全面的解决scheme,我将它包含在内。)

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

要看Swift 2演绎,请参阅此答案的以前的演绎 。

这可以通过在服务中传递所需的参数来完成,

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

这里的urlPath是包含web服务和locationCoord的url(作为最后一个参数)是web服务的location参数的运行时间值。 参数键,传感器,半径和types是固定的。

我在loginbutton点击调用json

 @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() } 

在这里,我已经为参数做了一个单独的字典。

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

基于上述我结束了这个,得到一个Set-Cookie元素中的一个令牌。

URLResponse在哪里

 <NSHTTPURLResponse: 0x17403ef20> { 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)! } } }