การร้องขอ HTTP ใน Swift ด้วยวิธี POST


189

ฉันพยายามเรียกใช้คำขอ HTTP ใน Swift ไปที่พารามิเตอร์ POST 2 ไปยัง URL

ตัวอย่าง:

Link: www.thisismylink.com/postName.php

params:

id = 13
name = Jack

วิธีที่ง่ายที่สุดในการทำเช่นนั้นคืออะไร?

ฉันไม่ต้องการอ่านคำตอบ ฉันแค่ต้องการส่งสิ่งนั้นเพื่อทำการเปลี่ยนแปลงในฐานข้อมูลของฉันผ่านไฟล์ PHP


คำตอบ:


411

ใน 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 ระดับสูง ซึ่งจะทำให้เปอร์เซ็นต์พารามิเตอร์ของแบบสอบถามถูกต้อง

หมายเหตุผมใช้nameของJack & Jillเพื่อแสดงให้เห็นเหมาะสมx-www-form-urlencodedผลของname=Jack%20%26%20Jillซึ่งเป็น“ร้อยละเข้ารหัส” (คือพื้นที่ที่จะถูกแทนที่ด้วย%20และ&ในค่าจะถูกแทนที่ด้วย%26)


ดูการแก้ไขคำตอบนี้ก่อนหน้าสำหรับการแปล Swift 2


7
FYI หากคุณต้องการทำคำขอจริง (รวมถึงเปอร์เซ็นต์การหลบหนีสร้างคำขอที่ซับซ้อนลดความซับซ้อนของการแยกคำตอบ) พิจารณาใช้AlamoFireจากผู้เขียนเครือข่าย AFN แต่ถ้าคุณเพียงแค่ต้องการทำเรื่องเล็กน้อยPOSTคุณสามารถใช้คำสั่งด้านบน
Rob

2
ขอบคุณ Rob นั่นคือสิ่งที่ฉันกำลังมองหา! ไม่มีอะไรมากไปกว่า POST ง่ายๆ คำตอบที่ดี!
Angeant

1
หลังจากสองสามชั่วโมงเพื่อค้นหาวิธีแก้ปัญหาที่แตกต่างกันบรรทัดที่ 3 และ 4 กำลังช่วยชีวิตฉันเนื่องจากฉันไม่สามารถใช้ชีวิตของฉันได้ NSJSONSerialization.dataWithJSONObject ทำงานได้!
Zork

1
@complexi - แทนที่จะวาดการเชื่อมต่อระหว่าง$_POSTและชื่อไฟล์ฉันจะลดสิ่งนี้ให้ง่ายขึ้น: สคริปต์ PHP จะไม่ทำงานเลยหากคุณไม่ได้รับ URL ที่ถูกต้อง แต่ไม่ใช่ทุกกรณีที่คุณต้องรวมชื่อไฟล์ (เช่นเซิร์ฟเวอร์อาจกำลังกำหนดเส้นทาง URL หรือมีชื่อไฟล์เริ่มต้น) ในกรณีนี้ OP ให้ URL ที่มีชื่อไฟล์ดังนั้นเราจึงใช้ URL เดียวกับที่เขาทำ
Rob

1
Alamofire ไม่ดีและไม่แย่ไปกว่าURLSessionนี้ API เครือข่ายทั้งหมดนั้นมีความสัมพันธ์แบบอะซิงโครนัสรวมอยู่ด้วยเช่นกัน ตอนนี้หากคุณกำลังมองหาวิธีการจัดการกับคำขอแบบอะซิงโครนัสอื่น ๆ ที่สง่างามคุณสามารถพิจารณาห่อ (ทั้งURLSessionคำขอหรือ Alamofire) ในแบบอะซิงโครนัสOperationซับคลาสที่กำหนดเอง หรือคุณสามารถใช้ห้องสมุดสัญญาเช่น PromiseKit
Rob

71

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

6
ฉันได้รับรหัสข้อผิดพลาดต่อไปนี้ของคุณ "ไม่สามารถอ่านข้อมูลได้เนื่องจากรูปแบบไม่ถูกต้อง"
applecrusher

ฉันคิดว่าคุณได้รับการตอบสนองในรูปแบบ String คุณสามารถตรวจสอบได้หรือไม่
Suhit Patil

1
ผมคิดว่าปัญหาที่เกิดขึ้นที่นี่ในการแก้ปัญหานี้คือการที่คุณผ่านพารามิเตอร์ JSON serializing และการบริการเว็บ takeing เป็นพารามิเตอร์ formdata
Amr โกรธ

ใช่ในการแก้ปัญหา params เป็น json โปรดตรวจสอบกับเซิร์ฟเวอร์หากต้องการข้อมูลแบบฟอร์มแล้วเปลี่ยนประเภทเนื้อหาเช่น request.setValue ("application / x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
Suhit Patil

สำหรับพารามิเตอร์หลายส่วนให้ใช้ boundaryConstant = "--V2ymHFg03ehbqgZCaKO6jy--"; request.addvalue ("หลายส่วน / ฟอร์ม - ขอบเขตข้อมูล = (ขอบเขตคงที่)", forHTTPHeaderField: "Content-Type")
Suhit Patil

18

สำหรับทุกคนที่กำลังมองหาวิธีที่ปลอดภัยในการเข้ารหัสคำขอ POST ใน Swift 5

คุณไม่จำเป็นต้องจัดการกับการเพิ่มเปอร์เซ็นต์การเข้ารหัสด้วยตนเอง ใช้URLComponentsเพื่อสร้าง URL คำขอ GET จากนั้นใช้queryคุณสมบัติของ URL นั้นเพื่อให้ได้รับสตริงข้อความค้นหาที่ใช้ค่า Escape อย่างเหมาะสม

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 เท่านั้น
Oleksandr

ฉันได้รับคำขอแมนชั่น แต่ฉันสงสัยว่าคำขอ POST เป็นอย่างไร จะส่งพารามิเตอร์ไปที่ httpBody หรือต้องการได้อย่างไร?
Mertalp Tasdelen

โซลูชันอัจฉริยะ! ขอบคุณที่แบ่งปัน @pointum ฉันแน่ใจว่า Martalp ไม่ต้องการคำตอบอีกต่อไป แต่สำหรับใครที่กำลังอ่านอยู่ข้างบนจะมีคำขอ POST
Vlad Spreys

12

นี่คือวิธีการที่ฉันใช้ในไลบรารีการบันทึกของฉัน: https://github.com/goktugyil/QorumLogs

วิธีนี้จะกรอกแบบฟอร์ม html ภายใน Google Forms

    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)

1
สิ่งที่application/x-www-form-urlencodedคุณจะตั้งค่าอะไร?
ฮันนี่มี. ค.

สำหรับการส่งผ่านข้อมูลในคำขอของร่างกาย @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")
        }

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

1
อันนี้อาจต้องมีการอัพเดทสำหรับ Swift 3/4 เพื่อใช้ URLRequest
Adam Ware

2

คำตอบทั้งหมดที่นี่ใช้วัตถุ JSON สิ่งนี้ทำให้เรามีปัญหากับ $this->input->post() วิธีการของตัวควบคุม Codeigniter ของเรา CI_Controllerไม่สามารถอ่าน JSON โดยตรง เราใช้วิธีนี้ในการทำโดยไม่ต้องใช้ JSON

fun 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 ของคุณจะสามารถรับparam1และparam2ใช้งาน$this->input->post('param1')และ$this->input->post('param2')

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.