Permintaan HTTP dalam Swift dengan metode POST

189

Saya mencoba menjalankan Permintaan HTTP di Swift, ke parameter POST 2 ke URL.

Contoh:

Tautan: www.thisismylink.com/postName.php

Params:

id = 13
name = Jack

Apa cara paling sederhana untuk melakukan itu?

Saya bahkan tidak ingin membaca jawabannya. Saya hanya ingin mengirim itu untuk melakukan perubahan pada database saya melalui file PHP.

angeant
sumber

Jawaban:

411

Dalam Swift 3 dan yang lebih baru Anda dapat:

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

Dimana:

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

Ini memeriksa kesalahan jaringan mendasar serta kesalahan HTTP tingkat tinggi. Ini juga benar persen lolos dari parameter permintaan.

Catatan, saya menggunakan namedari Jack & Jill, untuk menggambarkan tepat x-www-form-urlencodedhasil name=Jack%20%26%20Jill, yaitu “persen dikodekan” (yaitu ruang diganti dengan %20dan &dalam nilai diganti dengan %26).


Lihat revisi sebelumnya dari jawaban ini untuk rendisi Swift 2.

rampok
sumber
7
FYI, jika Anda ingin melakukan permintaan nyata (termasuk persen melarikan diri, membuat permintaan kompleks, menyederhanakan parsing tanggapan), pertimbangkan untuk menggunakan AlamoFire , dari penulis AFNetworking. Tetapi jika Anda hanya ingin melakukan POSTpermintaan sepele , Anda dapat menggunakan di atas.
Rob
2
Terima kasih Rob, Itulah yang saya cari! Tidak lebih dari POST sederhana. Jawaban bagus!
angeant
1
Setelah beberapa jam mencari beberapa solusi yang berbeda, jalur 3 dan 4 menyelamatkan hidup saya karena saya tidak bisa seumur hidup saya mendapatkan NSJSONSerialization.dataWithJSONObject untuk bekerja!
Zork
1
@complexi - Daripada menggambar koneksi antara $_POSTdan nama file, saya akan mengurangi ini menjadi sesuatu yang lebih sederhana: Skrip PHP tidak akan berjalan sama sekali jika Anda tidak mendapatkan URL yang benar. Tetapi tidak selalu Anda harus menyertakan nama file (mis. Server mungkin melakukan perutean URL atau memiliki nama file default). Dalam hal ini, OP memberi kami URL yang menyertakan nama file, jadi saya hanya menggunakan URL yang sama seperti dia.
Rob
1
Alamofire tidak lebih baik dan tidak lebih buruk daripada URLSessiondalam hal ini. Semua API jaringan pada dasarnya tidak sinkron, dan memang seharusnya demikian. Sekarang, jika Anda mencari cara lain untuk menangani permintaan asinkron, Anda dapat mempertimbangkan untuk membungkusnya (baik URLSessionpermintaan atau permintaan Alamofire) di Operationsubkelas asinkron, kustom . Atau Anda dapat menggunakan beberapa perpustakaan janji, seperti PromiseKit.
Rob
71

Cepat 4 dan lebih tinggi

@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()
}
Suhit Patil
sumber
6
Saya mendapatkan kesalahan berikut dengan kode Anda "Data tidak dapat dibaca karena tidak dalam format yang benar."
applecrusher
Saya pikir Anda mendapatkan respons dalam format String yang dapat Anda verifikasi?
Suhit Patil
1
saya pikir masalahnya di sini dalam solusi ini adalah bahwa Anda melewatkan parameter sebagai serialisasi json dan layanan web mengambil sebagai parameter formdata
Amr Angry
ya dalam solusi params adalah json, silakan periksa dengan server jika memerlukan formulir data kemudian ubah jenis konten misalnya request.setValue ("application / x-www-form-urlencoded", untukHTTPHeaderField: "Tipe-Konten")
Suhit Patil
untuk parar multipart gunakan let boundaryConstant = "--V2ymHFg03ehbqgZCaKO6jy--"; request.addvalue ("multipart / form-data boundary = (boundaryConstant)", forHTTPHeaderField: "Tipe-Konten")
Suhit Patil
18

Bagi siapa pun yang mencari cara bersih untuk menyandikan permintaan POST di Swift 5.

Anda tidak perlu berurusan dengan menambahkan pengodean persen secara manual. Gunakan URLComponentsuntuk membuat URL permintaan GET. Kemudian gunakan queryproperti dari URL itu untuk mendapatkan string kueri yang lolos dengan benar.

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

The queryakan menjadi string lolos benar:

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

Sekarang Anda dapat membuat permintaan dan menggunakan kueri sebagai HTTPBody:

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

Sekarang Anda dapat mengirim permintaan.

pointum
sumber
Setelah berbagai contoh, hanya ini yang berfungsi untuk Swift 5.
Oleksandr
Saya mendapatkan permintaan GET tapi saya bertanya-tanya bagaimana dengan permintaan POST? Bagaimana cara mengirimkan parameter ke httpBody atau apakah saya memerlukannya?
Mertalp Tasdelen
Solusi cerdas! Terima kasih telah berbagi @pointum. Saya yakin Martalp tidak membutuhkan jawaban lagi, tetapi untuk orang lain yang membaca, di atas melakukan permintaan POST.
Vlad Spreys
12

Inilah metode yang saya gunakan di perpustakaan logging saya: https://github.com/goktugyil/QorumLogs

Metode ini mengisi formulir html di dalam Formulir Google.

    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)
Esqarrouth
sumber
1
apa application/x-www-form-urlencodedyang kamu setting?
Sayang
Untuk melewatkan data di badan permintaan @Honey
Achraf
4
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")
        }
Osman
sumber
3
@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: [email protected] & 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()
}
Raish Khan
sumber
1
Yang ini mungkin perlu memperbarui untuk Swift 3/4 untuk menggunakan URLRequest
Adam Ware
2

Semua jawaban di sini menggunakan objek JSON. Ini memberi kami masalah dengan $this->input->post() metode pengontrol Codeigniter kami. The CI_Controllertidak bisa membaca JSON langsung. Kami menggunakan metode ini untuk melakukannya TANPA 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()
}

Sekarang CI_Controller Anda akan dapat memperoleh param1dan param2menggunakan $this->input->post('param1')dan$this->input->post('param2')

CanonicalBear
sumber