我正在尝试在Swift中运行HTTP请求,以将2个参数发布到URL。

示例:

链接:www.thisismylink.com/postName.php

参数:

id = 13
name = Jack


最简单的方法是什么?

我什至不想阅读响应。我只想发送该文件,以通过PHP文件对数据库进行更改。

评论

stackoverflow.com/a/48306950/6898523

#1 楼

在Swift 3和更高版本中,您可以:

let url = URL(string: "http://www.thisismylink.com/postName.php")!
var request = URLRequest(url: url)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
let parameters: [String: Any] = [
    "id": 13,
    "name": "Jack & Jill"
]
request.httpBody = parameters.percentEncoded()

let task = URLSession.shared.dataTask(with: request) { data, response, error in
    guard let data = data, 
        let response = response as? HTTPURLResponse, 
        error == nil else {                                              // check for fundamental networking error
        print("error", error ?? "Unknown error")
        return
    }

    guard (200 ... 299) ~= response.statusCode else {                    // check for http errors
        print("statusCode should be 2xx, but is \(response.statusCode)")
        print("response = \(response)")
        return
    }

    let responseString = String(data: data, encoding: .utf8)
    print("responseString = \(responseString)")
}

task.resume()


其中:

extension Dictionary {
    func percentEncoded() -> Data? {
        return map { key, value in
            let escapedKey = "\(key)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? ""
            let escapedValue = "\(value)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? ""
            return escapedKey + "=" + escapedValue
        }
        .joined(separator: "&")
        .data(using: .utf8)
    }
}

extension CharacterSet { 
    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
    }()
}


这将检查两个基本网络错误以及高级HTTP错误。这也可以正确地对查询的参数进行转义。

请注意,我使用了nameJack & Jill,以说明x-www-form-urlencoded的正确name=Jack%20%26%20Jill结果,该结果已“百分比编码”(即,空格替换为%20,值中的&替换为%26 )。


有关Swift 2演绎的信息,请参见此答案的先前版本。

评论


仅供参考,如果您要执行实际请求(包括转义百分比,创建复杂请求,简化响应解析),请考虑使用AFNetworking作者的AlamoFire。但是,如果您只想执行简单的POST请求,则可以使用上面的代码。

–Rob
2014年10月14日在16:07

谢谢Rob,那正是我想要的!只不过是一个简单的POST。好答案!

–愤怒
2014年10月14日下午16:58

在这方面,Alamofire并不比URLSession好,也没有比URLSession差。所有网络API本质上都是异步的,应该也是如此。现在,如果您正在寻找其他优雅的方式来处理异步请求,则可以考虑将它们(URLSession请求或Alamofire请求)包装在异步的自定义Operation子类中。或者,您可以使用一些Promise库,例如PromiseKit。

–Rob
'18 Apr 6在0:48



@DeepBlue-我明白您的意思,但我不同意。如果有问题,让自己静默失败是一个非常糟糕的主意。也许您可以警惕let url = ... else {fatalError(“ Invalid URL”)},但这在语法上毫无用处。您正在编写大量错误处理代码,而不是最终用户运行时问题,而是编程问题错误。类比是隐式展开的@IBOutlet引用。您是否为所有网点写了吨警戒标签= ...代码?不,那太傻了。同样在这里。

–Rob
19年5月24日在7:40

不要误会我的意思。如果某些事情不是立即显而易见的,或者由于程序员无法控制的原因而失败(例如解析JSON响应和/或处理网络错误),那么使用强制解包运算符是一个巨大的错误。绝对安全地拆开那些包装。但是对于@IBOutlet之类的内容或该URL示例,则添加这种语法噪音IMHO适得其反。而且,要使用只返回的else子句进行保护,隐藏任何潜在的问题,是一个非常糟糕的主意。

–Rob
19年5月24日在7:41

#2 楼

Swift 4及更高版本

@IBAction func submitAction(sender: UIButton) {

    //declare parameter as a dictionary which contains string as key and value combination. considering inputs are valid

    let parameters = ["id": 13, "name": "jack"]

    //create the url with URL
    let url = URL(string: "www.thisismylink.com/postName.php")! //change the url

    //create the session object
    let session = URLSession.shared

    //now create the URLRequest object using the url object
    var request = URLRequest(url: url)
    request.httpMethod = "POST" //set http method as POST

    do {
        request.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted) // pass dictionary to nsdata object and set it as request body
    } catch let error {
        print(error.localizedDescription)
    }

    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.addValue("application/json", forHTTPHeaderField: "Accept")

    //create dataTask using the session object to send data to the server
    let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in

        guard error == nil else {
            return
        }

        guard let data = data else {
            return
        }

        do {
            //create json object from data
            if let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
                print(json)
                // handle json...
            }
        } catch let error {
            print(error.localizedDescription)
        }
    })
    task.resume()
}


评论


我的代码出现以下错误:“数据格式不正确,因此无法读取”。

–applecrusher
16 Dec 13'在16:28

我认为您收到的字符串格式的响应可以验证吗?

– Suhit Patil
16 Dec 14'2:41

我认为此解决方案中的问题是您将参数传递为json序列化,并且Web服务将其作为formdata参数

–愤怒
17年2月15日在11:46

是的,在解决方案中参数为json,请与服务器检查是否需要表单数据,然后更改内容类型,例如request.setValue(“ application / x-www-form-urlencoded”,forHTTPHeaderField:“ Content-Type”)

– Suhit Patil
17年2月15日在12:51

对于多部分参数,请使用let boundaryConstant =“ --V2ymHFg03ehbqgZCaKO6jy--”; request.addvalue(“ multipart / form-data boundary =(boundaryConstant)”,对于HTTPHeaderField:“ Content-Type”)

– Suhit Patil
17-2-15在13:05



#3 楼

对于寻求在Swift 5中对POST请求进行编码的干净方法的人。

您无需手动添加百分比编码。
使用URLComponents创建GET请求URL。然后使用该URL的query属性正确获取转义百分比的查询字符串。

let url = URL(string: "https://example.com")!
var components = URLComponents(url: url, resolvingAgainstBaseURL: false)!

components.queryItems = [
    URLQueryItem(name: "key1", value: "NeedToEscape=And&"),
    URLQueryItem(name: "key2", value: "vålüé")
]

let query = components.url!.query


query将是正确转义的字符串:


key1 = NeedToEscape%3DAnd%26&key2 = v%C3%A5l%C3%BC%C3%A9


现在您可以创建请求并将查询用作HTTPBody:

var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = Data(query.utf8)


现在您可以发送请求。

评论


在各种示例之后,只有这适用于Swift 5。

–夹竹桃
1月7日9:19

我提出了GET请求,但我不知道POST请求如何?如何将参数传递到httpBody或我需要它?

– Mertalp Tasdelen
1月31日22:30

智能解决方案!感谢您分享@pointum。我确定Martalp不再需要答案了,但是对于其他阅读的人,上面的请求是POST。

– Vlad Spreys
5月13日22:04

#4 楼

这是我在日志记录库中使用的方法:https://github.com/goktugyil/QorumLogs

此方法填充Google Forms中的html表单。

    var url = NSURL(string: urlstring)

    var request = NSMutableURLRequest(URL: url!)
    request.HTTPMethod = "POST"
    request.setValue("application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type")
    request.HTTPBody = postData.dataUsingEncoding(NSUTF8StringEncoding)
    var connection = NSURLConnection(request: request, delegate: nil, startImmediately: true)


评论


什么是application / x-www-form-urlencoded您要设置什么?

–蜂蜜
17 Mar 24 '17 at 20:09

用于在请求正文中传递数据@Honey

–阿赫拉夫
18/09/10在10:57



#5 楼

let session = URLSession.shared
        let url = "http://...."
        let request = NSMutableURLRequest(url: NSURL(string: url)! as URL)
        request.httpMethod = "POST"
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        var params :[String: Any]?
        params = ["Some_ID" : "111", "REQUEST" : "SOME_API_NAME"]
        do{
            request.httpBody = try JSONSerialization.data(withJSONObject: params, options: JSONSerialization.WritingOptions())
            let task = session.dataTask(with: request as URLRequest as URLRequest, completionHandler: {(data, response, error) in
                if let response = response {
                    let nsHTTPResponse = response as! HTTPURLResponse
                    let statusCode = nsHTTPResponse.statusCode
                    print ("status code = \(statusCode)")
                }
                if let error = error {
                    print ("\(error)")
                }
                if let data = data {
                    do{
                        let jsonResponse = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions())
                        print ("data = \(jsonResponse)")
                    }catch _ {
                        print ("OOps not good JSON formatted response")
                    }
                }
            })
            task.resume()
        }catch _ {
            print ("Oops something happened buddy")
        }


#6 楼

这里的所有答案都使用JSON对象。这给我们Codeigniter控制器的
$this->input->post()
方法带来了问题。 CI_Controller无法直接读取JSON。
我们使用此方法无需JSON
 func postRequest() {
    // Create url object
    guard let url = URL(string: yourURL) else {return}

    // Create the session object
    let session = URLSession.shared

    // Create the URLRequest object using the url object
    var request = URLRequest(url: url)

    // Set the request method. Important Do not set any other headers, like Content-Type
    request.httpMethod = "POST" //set http method as POST

    // Set parameters here. Replace with your own.
    let postData = "param1_id=param1_value&param2_id=param2_value".data(using: .utf8)
    request.httpBody = postData

    // Create a task using the session object, to run and return completion handler
    let webTask = session.dataTask(with: request, completionHandler: {data, response, error in
    guard error == nil else {
        print(error?.localizedDescription ?? "Response Error")
        return
    }
    guard let serverData = data else {
        print("server data error")
        return
    }
    do {
        if let requestJson = try JSONSerialization.jsonObject(with: serverData, options: .mutableContainers) as? [String: Any]{
            print("Response: \(requestJson)")
        }
    } catch let responseError {
        print("Serialisation in error in creating response body: \(responseError.localizedDescription)")
        let message = String(bytes: serverData, encoding: .ascii)
        print(message as Any)
    }

    // Run the task
    webTask.resume()
}
 

现在您的CI_Controller将能够使用param1param2获得$this->input->post('param1')$this->input->post('param2')

#7 楼

@IBAction func btn_LogIn(sender: AnyObject) {

    let request = NSMutableURLRequest(URL: NSURL(string: "http://demo.hackerkernel.com/ios_api/login.php")!)
    request.HTTPMethod = "POST"
    let postString = "email: test@test.com & password: testtest"
    request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
    let task = NSURLSession.sharedSession().dataTaskWithRequest(request){data, response, error in
        guard error == nil && data != nil else{
            print("error")
            return
        }
        if let httpStatus = response as? NSHTTPURLResponse where httpStatus.statusCode != 200{
            print("statusCode should be 200, but is \(httpStatus.statusCode)")
            print("response = \(response)")
        }
        let responseString = String(data: data!, encoding: NSUTF8StringEncoding)
        print("responseString = \(responseString)")
    }
    task.resume()
}


评论


可能需要更新Swift 3/4才能使用URLRequest

–亚当·韦尔(Adam Ware)
19年1月20日,下午3:34