Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/120.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 在Swift中传递WebService中的参数_Ios_Swift - Fatal编程技术网

Ios 在Swift中传递WebService中的参数

Ios 在Swift中传递WebService中的参数,ios,swift,Ios,Swift,我正在学习Swift,我不知道如何使用Swift向服务器发送参数。 在Objective-C中,我们可以使用“%@”作为占位符。 但是,在使用Swift的情况下应该怎么做呢?假设我有一个需要电子邮件和密码的登录Web服务 现在我想知道的是如何将logintextfield和passwordtextfield文本发送到服务器,例如 var bodyData = "email=logintextfield.text&password=passwordtextfield.text" 创建包含

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

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

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

创建包含用户输入的HTTP请求时,如果用户输入中有任何保留字符,通常应转义该请求,因此:

let login    = logintextfield.text?.addingPercentEncodingForURLQueryValue() ?? ""
let password = passwordtextfield.text?.addingPercentEncodingForURLQueryValue() ?? ""
let bodyData = "email=\(login)&password=\(password)"
注意,您确实需要检查
login
password
是否为
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()
我包含了很多您的示例中没有包含的参数,只是为了说明例程对各种参数类型的处理

顺便说一句,上面使用my
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)!
    }

}
在这里,因为我处理的是一个参数字符串数组,所以我使用
join
函数将它们连接起来,由
&
分隔,但思想是一样的

请随意定制该函数,以处理您可能传递到其中的任何数据类型(例如,我通常没有
CLLocationCoordinate2D
,但您的示例中包含了一个,因此我想展示它的外观)。但关键是,如果您提供的任何字段都包含用户输入,请确保转义它

仅供参考,这是我的
rfc3339String
函数,上面使用了该函数。(显然,如果您不需要传输日期,也不需要这样做,但为了完整起见,我将其包括在内,以获得更通用的解决方案。)


要查看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服务的url,
locationCoord
(作为最后一个参数)是web服务位置参数的运行时值。参数键、传感器、半径和类型是固定的

我正在调用登录时的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
     }

基于以上内容,我最终得出结论,在一个集合Cookie元素中获取一个令牌

响应的位置

<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)!
        }
    }
}
{URL:http://bla.co.uk//auth/authenticate?email=bob@isp.eu&password=xcode}{状态代码:200,头{
“缓存控制”=“专用,必须重新验证”;
连接=“保持活动”;
“内容类型”=“应用程序/json”;
日期=“2017年2月17日星期五10:51:41 GMT”;
Expires=“-1”;
Pragma=“无缓存”;
服务器=nginx;
“设置Cookie”=“令牌=Cu4CmOaverylongstring0mCu4CmOpBGg;过期日期=2017年2月17日星期五20:51:41 GMT;最大期限=36000;路径=身份验证;仅限httponly”;
“传输编码”=标识;
“X-Powered-By”=“PHP/5.5.9-1ubuntu4.19,PleskLin”;
} }
func urlSession(session:urlSession,dataTask:URLSessionDataTask,didReceive响应:URLResponse,completionHandler:@escaping(urlSession.ResponseDisposition)->Void){
让httpResponse=响应为!HTTPURLResponse
让statusCode=httpResponse.statusCode
如果statusCode==200{
让keyValues=httpResponse.allHeaderFields.map{(字符串(描述:$0.key).lowercased(),字符串(描述:$0.value))}
//现在过滤数组,搜索头键(也是小写的)
如果让myHeaderValue=keyValues.filter({$0.0==“Set Cookie”.lowercased()})。首先{
打印(myHeaderValue.1)
让cookies=myHeaderValue.1
让cookieDict=cookies.components(以“;”分隔)
打印(“\(cookieDict)”)
让tokenEntryParameter=cookieDict.filter({$0.contains(“token”)})
让tokenEntry=tokenEntryParameter.first
token=(tokenEntry?.components(以“=”).last分隔)!
}
}
}

是的,你帮了我。。!!很明显,你永远不会像你的问题中那样在URL中添加用户ID或密码,因为这不是很安全。这些将始终放在请求正文中。@Rob您的意思是,在向服务器发送用户ID或密码时,我必须将它们放在请求正文中??请解释一下。是的,这通常是被建议的,因为URL并不十分安全(你可能会发现它们隐藏在服务器或其他地方的web日志中)。一般来说,人们建议在
POST
请求中发送安全信息,而不是在URL本身中。我从您的
bodyData
变量名推断,您已经在请求正文中包含了这些HTTP请求参数,但根据这个答案(URL中包含了这些参数),我不清楚。@Rob我明白您的意思了。我编写以下代码,let keyData=“AIzaSyCRLa4LQZWNQBcjCYcIVYA45i9i8zfClqc”let sensorData=“false”let typesData=“restaurant”let radiudata=“1000000”let coord=locationCoord let bodyData=“key=“+keyData+”&sensor=“+sensorData+”&types=“+typesData+”&radius=“+radiusaat+”&location=”+coored println(“完整数据是(bodyData)”),这里coored是lat和长连接。然后我把主体数据命名为request.HTTPBody=bodyData。这是正确的吗?你能给我一些示例代码吗。谢谢。请参阅我修改后的答案,其中包括示例(可能比您需要的更多,但说明了概念)。
<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)!
        }
    }
}