POST 메소드를 사용하여 Swift의 HTTP 요청


189

Swift에서 HTTP 요청을 실행하여 URL에 2 개의 매개 변수를 POST하려고합니다.

예:

링크: www.thisismylink.com/postName.php

매개 변수 :

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 오류를 모두 확인합니다. 또한이 비율은 쿼리의 매개 변수를 올바르게 이스케이프합니다.

참고, I는 사용 name중을 Jack & Jill적절한 예시하는 x-www-form-urlencoded결과 name=Jack%20%26%20Jill(즉, 공간으로 치환 "퍼센트 인코딩"이고, %20상기 &가치가 대체된다 %26).


Swift 2 변환에 대한 이 답변의 이전 개정판을 참조하십시오 .


7
당신이 진짜 요청을 수행하려는 경우 참고로, 사용을 고려 (복잡한 요청을 생성 %의 탈출을 포함하여, 응답의 분석을 단순화) AlamoFire을 AFNetworking의 저자에서. 그러나 간단한 POST요청을 원한다면 위의 내용을 사용할 수 있습니다.
Rob

2
고마워 Rob, 그게 내가 찾던 것이 었어! 단순한 POST 이상의 것은 없습니다. 좋은 답변입니다!
angeant

1
몇 가지 다른 솔루션을 찾은 후 3 줄과 4 줄은 NSJSONSerialization.dataWithJSONObject가 작동하도록 할 수 없어서 생명을 구하고 있습니다.
Zork

1
@complexi- $_POST파일 이름과 연결을 그리는 대신 이것을 간단한 것으로 줄 이겠습니다 . URL이 정확하지 않으면 PHP 스크립트가 전혀 실행되지 않습니다. 그러나 항상 파일 이름을 포함시켜야하는 것은 아닙니다 (예 : 서버가 URL 라우팅을 수행 중이거나 기본 파일 이름을 가질 수 있음). 이 경우 OP는 파일 이름이 포함 된 URL을 제공 했으므로 단순히 그가했던 것과 동일한 URL을 사용했습니다.
Rob

1
Alamofire는 URLSession이 점 보다 나쁘지 않습니다 . 모든 네트워킹 API는 본질적으로 비동기 적이어야합니다. 이제 비동기식 요청을 처리하는 다른 우아한 방법을 찾고 있다면 URLSession비동기식 사용자 정의 Operation서브 클래스로 요청 ( 알람 또는 Alamofire)을 래핑하는 것을 고려할 수 있습니다 . 또는 PromiseKit과 같은 일부 약속 라이브러리를 사용할 수 있습니다.
Rob

71

스위프트 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

문자열 형식으로 응답을 받고 있다고 생각할 수 있습니까?
Suhit Patil

1
이 솔루션의 문제는 json 직렬화로 매개 변수를 전달하고 웹 서비스가 formdata 매개 변수로 사용한다는 것입니다.
Amr Angry

예 솔루션에서 매개 변수가 json 인 경우 양식 데이터가 필요한 경우 서버에 확인한 다음 내용 유형을 변경하십시오. request.setValue ( "application / x-www-form-urlencoded", forHTTPHeaderField : "Content-Type")
Suhit Patil

멀티 파트 매개 변수의 경우 let boundaryConstant = "--V2ymHFg03ehbqgZCaKO6jy--"; request.addvalue ( "multipart / form-data boundary = (boundaryConstant)", forHTTPHeaderField : "Content-Type")
Suhit Patil 2012

18

Swift 5에서 POST 요청을 깔끔하게 인코딩하는 방법을 찾는 사람이라면 누구나 가능합니다.

퍼센트 인코딩을 수동으로 추가 할 필요가 없습니다. URLComponentsGET 요청 URL을 작성하는 데 사용하십시오 . 그런 다음 query해당 URL의 속성을 사용 하여 이스케이프 된 쿼리 문자열을 올바르게 가져옵니다.

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 = 필요한 이스케이프 % 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

GET 요청을 저술했지만 POST 요청은 어떻습니까? httpBody에 매개 변수를 전달하는 방법 또는 필요합니까?
Mertalp Tasdelen

똑똑한 솔루션! @pointum을 공유해 주셔서 감사합니다. 나는 Martalp이 더 이상 대답을 필요로하지 않는다고 확신하지만 다른 누군가를 읽으려면 위의 POST 요청을 수행합니다.
Vlad Spreys

12

로깅 라이브러리에서 사용한 방법은 다음과 같습니다. https://github.com/goktugyil/QorumLogs

이 메소드는 Google 설문지 내의 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)

1
무엇 application/x-www-form-urlencoded을 설정하고 있습니까?
Honey

요청 본문에 데이터를 전달하는 경우 @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를 사용하려면 Swift 3/4를 업데이트해야합니다.
Adam Ware

2

여기에있는 모든 답변은 JSON 객체를 사용합니다. 이로 인해 $this->input->post() Codeigniter 컨트롤러 의 방법에 문제가 발생했습니다 . 는 CI_ControllerJSON을 직접 읽을 수 없습니다. 우리는이 방법을 사용하여 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는 param1and를 param2사용 $this->input->post('param1')하고 사용할 수 있습니다.$this->input->post('param2')

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.