POST with swift and API

后端 未结 3 1872
孤街浪徒
孤街浪徒 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:12

    the following php code is for receiving application/url+encode encoded post message. please refer https://en.wikipedia.org/wiki/Percent-encoding

    $_POST["pseudo"]
    

    and your swift code was sending a JSON encoded string data. They are incompatible.

    If you don't want to change the php code, in Swift you should send url-encode format message, li:

    // UPDATED with corrections from @Rob

        var params = ["param1":"value1", "papam2": "value 2"]
        var body = ""
        for (key, value) in params {
            body = body.stringByAppendingString(key)
            body = body.stringByAppendingString("=")
            body = body.stringByAppendingString(value.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!)
            body = body.stringByAppendingString("&")
        }
        body = body.substringToIndex(advance(body.startIndex, countElements(body)-1)) // remove the last "&"
        request.HTTPBody = body.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
    
    0 讨论(0)
  • 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.

    0 讨论(0)
  • Try this:

     let myURL = NSURL(string: "http://localhost:8888/academy/test.php")! 
     let request = NSMutableURLRequest(URL: myURL)
     request.HTTPMethod = "POST"
     request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
     request.setValue("application/json", forHTTPHeaderField: "Accept")
     let bodyStr:String = "pseudo=test"
     request.HTTPBody = bodyStr.dataUsingEncoding(NSUTF8StringEncoding) 
     let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
          data, response, error in
    
          // Your completion handler code here
     }
     task.resume()
    

    You have to encode your data using UTF8 string encoding. If you need to set more than one field&value pairs for request body, you can change the body string, for example, "pseudo=test&language=swift". In fact, I usually create an extension for NSMutableURLRequest and add a method which takes a dictionary as parameter and sets the content of this map(dictionary) as HTTPBody using correct encoding. This may work for you:

     extension NSMutableURLRequest {
          func setBodyContent(contentMap: Dictionary<String, String>) {
               var firstOneAdded = false
               let contentKeys:Array<String> = Array(contentMap.keys)
               for contentKey in contentKeys {
                    if(!firstOneAdded) {
                         contentBodyAsString += contentKey + "=" + contentMap[contentKey]!
                         firstOneAdded = true
                    }
                    else {
                         contentBodyAsString += "&" + contentKey + "=" + contentMap[contentKey]! 
                    }
               }
               contentBodyAsString = contentBodyAsString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
               self.HTTPBody = contentBodyAsString.dataUsingEncoding(NSUTF8StringEncoding)
          }
     }
    

    And you can use this as:

    request.setBodyContent(params)
    

    I hope this helps you!

    0 讨论(0)
提交回复
热议问题