Swift'te POST yöntemiyle HTTP İsteği


189

Swift, bir URL POST 2 parametreleri için bir HTTP isteği çalıştırmak çalışıyorum.

Misal:

Bağlantı: www.thisismylink.com/postName.php

parametreler:

id = 13
name = Jack

Bunu yapmanın en basit yolu nedir?

Cevabı okumak bile istemiyorum. Sadece bir PHP dosyası aracılığıyla veritabanımda değişiklikler yapmak için göndermek istiyorum.


Yanıtlar:


411

Swift 3 ve sonrasında şunları yapabilirsiniz:

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

Nerede:

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

Bu, hem temel ağ hatalarını hem de üst düzey HTTP hatalarını kontrol eder. Bu da düzgün bir şekilde yüzde sorgu parametrelerini kaçar.

Not, bir kullanılmış nameve Jack & Jilluygun göstermek için, x-www-form-urlencodedsonucunu name=Jack%20%26%20Jill(yani boşluk ile değiştirilir “yüzde kodlanmış” dir, %20ve &değeri ile değiştirilir %26).


Swift 2 yorumlaması için bu cevabın önceki revizyonuna bakın .


7
FYI, gerçek talepler yapmak istiyorsanız (kaçma yüzdesi, karmaşık istekler oluşturma, yanıtların ayrıştırılmasını basitleştirme dahil), AFNetworking'in yazarı AlamoFire'ı kullanmayı düşünün. Ancak sadece önemsiz bir POSTistekte bulunmak istiyorsanız, yukarıdakileri kullanabilirsiniz.
Rob

2
Teşekkürler Rob, Aradığım şey buydu! Basit bir POST'tan başka bir şey yok. Mükemmel cevap!
angeant

1
Birkaç farklı çözüm aradıktan birkaç saat sonra, 3. ve 4. satırlar hayatımı kurtarıyor çünkü hayatım boyunca NSJSONSerialization.dataWithJSONObject'i çalıştıramadım!
Zork

1
@complexi - $_POSTDosya ve dosya adları arasındaki bağlantıları çizmek yerine , bunu daha basit bir şeye indirgeyeceğim: URL'yi doğru şekilde almazsanız PHP komut dosyası hiç çalışmaz. Ancak dosya adını eklemeniz her zaman böyle değildir (örneğin, sunucu URL yönlendirme yapıyor olabilir veya varsayılan dosya adlarına sahip olabilir). Bu durumda, OP bize bir dosya adı içeren bir URL verdi, bu yüzden onunla aynı URL'yi kullandım.
Rob

1
Alamofire URLSessionbu bakımdan daha iyi ve daha kötü değildir . Tüm ağ API'leri doğal olarak eşzamansızdır ve olması gerekir. Şimdi, eşzamansız isteklerle uğraşmanın diğer zarif yollarını arıyorsanız, bunları ( URLSessionistekleri veya Alamofire isteklerini) eşzamansız, özel Operationalt sınıfa sarmayı düşünebilirsiniz . Veya PromiseKit gibi bazı vaat kütüphanelerini kullanabilirsiniz.
Rob

71

Swift 4 ve üstü

@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
Kodunuzda "Doğru biçimde olmadığı için veriler okunamadı" hatasıyla karşılaşıyorum.
applecrusher

Sanırım String biçiminde yanıt alıyorsunuz doğrulayabilir misiniz?
Suhit Patil

1
Ben burada bu çözümde sorun json serileştirme olarak parametre geçmek ve web hizmeti formdata parametreleri olarak alıyor olduğunu düşünüyorum
Amr Angry

evet çözümde parametreler json, lütfen form verileri gerektiriyorsa sunucuya danışın ve içerik türünü değiştirin, örneğin request.setValue ("application / x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
Suhit Patil

çok parçalı parametreler için let boundaryConstant = "--V2ymHFg03ehbqgZCaKO6jy--"; request.addvalue ("çoklu bölüm / form-veri sınırı = (boundaryConstant)", forHTTPHeaderField: "İçerik Tipi")
Suhit Patil

18

Swift 5'te bir POST isteğini kodlamanın temiz bir yolunu arayan herkes için.

Manuel olarak yüzde kodlaması eklemekle uğraşmanıza gerek yoktur. URLComponentsBir GET istek URL'si oluşturmak için kullanın . Ardından query, kaçan sorgu dizesinin yüzdesini düzgün bir şekilde almak için bu URL'nin özelliğini kullanın .

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

queryDüzgün kaçan dize olacaktır:

anahtar1 = NeedToEscape% 3DAnd% 26 ve anahtar2 = hacim olarak% C3% A5L% C3% BC% C3% A9

Şimdi bir istek oluşturabilir ve sorguyu HTTPBody olarak kullanabilirsiniz:

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

Şimdi isteği gönderebilirsiniz.


Çeşitli örneklerden sonra, bu sadece Swift 5 için çalışır
Oleksandr

Ben istek AL konak ama ben POST isteği hakkında merak? Parametreleri httpBody'e nasıl geçirebilirim veya buna ihtiyacım var mı?
Mertalp Tasdelen

Akıllı çözüm! @Pointum'u paylaştığınız için teşekkür ederiz. Eminim Martalp'ın artık cevaba ihtiyacı yok, ama okuyan herkes için yukarıdakilerin POST isteği var.
Vlad Spreys

12

Günlük kütüphanemde kullandığım yöntem heres: https://github.com/goktugyil/QorumLogs

Bu yöntem, Google Formlar içindeki html formlarını doldurur.

    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
Ne application/x-www-form-urlencodedayarlıyorsun?
Tatlım

İstek gövdesinde veri aktarmak için @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
URLRequest'i kullanmak için Swift 3/4'ün güncellenmesi gerekebilir
Adam Ware

2

Buradaki tüm cevaplar JSON nesnelerini kullanır. Bu bize $this->input->post() Codeigniter kontrolörlerimizin yöntemleri ile ilgili sorunlar verdi . CI_ControllerJSON doğrudan okuyabilir değil. JSON OLMADAN bunu yapmak için bu yöntemi kullandık

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

Şimdi CI_Controller almak mümkün olacak param1ve param2kullanma $this->input->post('param1')ve$this->input->post('param2')

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.