发送帖子数据nsurlsession

时间:2015-06-24 13:16:12

标签: json swift post nsurlsession

您好我正试图在操场上使用NSURLSession在swift中复制以下curl命令。

curl -k -i -H“接受:application / json”-H“X-Application:” - X POST -d'username =& password ='https://address.com/api/login

这是我到目前为止所得到的。我在努力的地方是我不确定如何发送帖子数据,例如:'username =& password ='。任何帮助将不胜感激。

提前致谢。

import Foundation
import XCPlayground

// Let asynchronous code run
XCPSetExecutionShouldContinueIndefinitely()



let config = NSURLSessionConfiguration.defaultSessionConfiguration()
config.HTTPAdditionalHeaders = ["Accept" : "application/json", "X-Application" : "<AppKey>"]


let session = NSURLSession(configuration: config)


var running = false
let url = NSURL(string: "https://address.com/api/login")
let task = session.dataTaskWithURL(url!) {
   (let data, let response, let error) in
   if let httpResponse = response as? NSHTTPURLResponse {
      let dataString = NSString(data: data, encoding: NSUTF8StringEncoding)
      println(dataString)
   }
   running = false
}

running = true
task.resume()

2 个答案:

答案 0 :(得分:3)

您可以创建一个可变URLRequest并设置httpBody。但是你也应该逃避username的值,更重要的是password的值。

因此,想象一下您的请求是这样创建的:

let config = URLSessionConfiguration.default
config.httpAdditionalHeaders = ["Accept" : "application/json", "X-Application" : "<AppKey>", "Content-Type" : "application/x-www-form-urlencoded"]

let session = URLSession(configuration: config)

let url = URL(string: "https://identitysso.betfair.com/api/login")!

var request = URLRequest(url: url)
request.setBodyContent(["username": username, "password": password])

let task = session.dataTask(with: request) { data, response, error in
    // make sure there wasn't a fundamental networking error

    guard let data = data, let response = response as? HTTPURLResponse, error == nil else {
        print(error ?? "Unknown error")
        return
    }

    // if you're going to check for NSHTTPURLResponse, then do something useful
    // with it, e.g. see if server status code indicates that everything is OK

    guard 200 ..< 300 ~= response.statusCode else {
        print("statusCode not 2xx; was \(response.statusCode)")
        return
    }

    // since you set `Accept` to JSON, I'd assume you'd want to parse it;
    // In Swift 4 and later, use JSONDecoder; in Swift 3 use JSONSerialization

    do {
        if let responseObject = try JSONSerialization.jsonObject(with: data) as? [String: AnyObject] {
            print(responseObject)
        }
    } catch let parseError {
        print(parseError)
        print(String(data: data, encoding: .utf8) ?? data as NSData)
    }
}

task.resume()

所以问题是setBodyContent如何在给定字典的情况下构建请求体。是的,你希望百分之百逃避任何不在未保留字符集中的东西,但遗憾的是CharacterSet.urlQueryAllowed不能胜任这项工作。所以你可以这样做:

extension URLRequest {

    /// Populate the HTTPBody of `application/x-www-form-urlencoded` request
    ///
    /// - parameter parameters:   A dictionary of keys and values to be added to the request

    mutating func setBodyContent(_ parameters: [String : String]) {
        let parameterArray = parameters.map { (key, value) -> String in
            let encodedKey   = key.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed)!
            let encodedValue = value.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed)!
            return "\(encodedKey)=\(encodedValue)"
        }
        httpBody = parameterArray
            .joined(separator: "&")
            .data(using: .utf8)
    }
}

extension CharacterSet {

    /// Character set containing characters allowed in query value as outlined in RFC 3986.
    ///
    /// RFC 3986 states that the following characters are "reserved" characters.
    ///
    /// - General Delimiters: ":", "#", "[", "]", "@", "?", "/"
    /// - Sub-Delimiters: "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "="
    ///
    /// In RFC 3986 - Section 3.4, it states that the "?" and "/" characters should not be escaped to allow
    /// query strings to include a URL. Therefore, all "reserved" characters with the exception of "?" and "/"
    /// should be percent-escaped in the query string.
    ///
    /// - parameter string: The string to be percent-escaped.
    ///
    /// - returns: The percent-escaped string.

    static let urlQueryValueAllowed: CharacterSet = {
        let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4
        let subDelimitersToEncode = "!$&'()*+,;="

        var allowed = CharacterSet.urlQueryAllowed
        allowed.remove(charactersIn: generalDelimitersToEncode + subDelimitersToEncode)

        return allowed
    }()

}

此外,我通常使用更复杂的setBodyContent,它也接受数字,布尔和日期类型,但我不想离开你的核心问题太远,如何正确构建请求两个字符串键/值对。

对于Swift 2的演绎,请参阅previous revision of this answer

答案 1 :(得分:1)

也许这个帮助,我用它来发送帖子数据:

var paramString = ""
var request:NSMutableURLRequest = NSMutableURLRequest(URL:url)
request.HTTPMethod = "POST"
var user = "MyUsername".stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
var pass = "MyPassword".stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
paramString = "username="+user!+"&password="+pass!
request.HTTPBody = paramString.dataUsingEncoding(NSUTF8StringEncoding)
let conf: NSURLSessionConfiguration = NSURLSession.sharedSession().configuration
let session = NSURLSession(configuration: conf)
session.dataTaskWithRequest(request) {
    data, response, error in
    let resp = NSString(data: data, encoding: NSUTF8StringEncoding)
    }.resume()

NSUTF8StringEncoding可以替换为您需要的任何内容