POST with swift and API

后端 未结 3 1878
孤街浪徒
孤街浪徒 2020-12-09 07:05

I\'ve a problem when I try to send a POST request to my API on my server, I\'ve followed many many different tutorials but it still doesn\'t work. I know than my problem is

3条回答
  •  我在风中等你
    2020-12-09 07:14

    As others have pointed out, the encoding of the request is not quite right. Your server code is not expecting JSON request, but rather is using $_POST variables (which means that the request should have Content-Type of application/x-www-form-urlencoded). So that's what you should create. For example in Swift 3 and later:

    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    
    let parameters = ["somekey" : "valueforkey"]
    request.setContent(with: parameters)
    
    let task = session.dataTask(with: request) { data, response, error in
        guard let data = data, error == nil else {
            print(error ?? "Unknown error")
            return
        }
        // your response parsing code here
    }
    task.resume()
    

    The setContent method would take a dictionary of the form ["key1": "foo", "key2" : "bar"] and populate the httpBody with something that looks like key1=foo&key2=bar. If you do that, the server will be able to parse the $_POST from the request.

    extension URLRequest {
        /// Set body and header for x-www-form-urlencoded request
        ///
        /// - Parameter parameters: Simple string dictionary of parameters to be encoded in body of request
    
        mutating func setContent(with parameters: [String: String]) {
            setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
    
            let array = parameters.map { entry -> String in
                let key = entry.key.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed)!
                let value = entry.value.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed)!
                return key + "=" + value
            }
            httpBody = array.joined(separator: "&").data(using: .utf8)!
        }
    }
    

    Note, this also percent-encodes the values (and, just in case, the keys, too), which is critical. While others have advised using addingPercentEncoding with .urlQueryAllowed, sadly that will not do the job, as it will let certain reserved characters (notably +) pass unescaped. Most web services will interpret the + as a space, in conformance with the x-www-form-urlencoded spec. So, adapting an approach adopted by Alamofire, I define a character set which will encode values with the various delimiters:

    extension CharacterSet {
    
        /// Returns the character set for characters allowed in the individual parameters within a query URL component.
        ///
        /// The query component of a URL is the component immediately following a question mark (?).
        /// For example, in the URL `http://www.example.com/index.php?key1=value1#jumpLink`, the query
        /// component is `key1=value1`. The individual parameters of that query would be the key `key1`
        /// and its associated value `value1`.
        ///
        /// According to RFC 3986, the set of unreserved characters includes
        ///
        /// `ALPHA / DIGIT / "-" / "." / "_" / "~"`
        ///
        /// In section 3.4 of the RFC, it further recommends adding `/` and `?` to the list of unescaped characters
        /// for the sake of compatibility with some erroneous implementations, so this routine also allows those
        /// to pass unescaped.
    
        static var 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
        }()
    }
    

    For Swift 2 rendition, see previous revision of this answer.

提交回复
热议问题