1

The code below is based on this excellent SO answer for making POST requests on iOS. This code attempts to make a POST request to:

http://requestb.in/14090od1

The request works if there is no value for the httpBody property of the URLRequest object, or if the value is only the empty string.

However, once a non-empty value is assigned to httpBody, the request times out.

Anyone know why?

// Succeeds
let userOptions = ["url": "http://requestb.in/14090od1"]
userOptions["bodyString" : ""]
doPost(userOptions: userOptions)

// Fails
let userOptions = ["url": "http://requestb.in/14090od1"]
userOptions["bodyString" : "hi"]
doPost(userOptions: userOptions)


fileprivate func doPost(userOptions: [String:Any]) {
    // Get URL string
    let urlString = userOptions["url"] as? String ?? ""

    // If invalid URL, return early
    guard let url = URL(string: urlString) else {
        printError("Error in doPost: malformed URL")
        return
    }

    // If here, URL valid so execute request
    // Create request
    var request = URLRequest(url: url)

    // Add headers
    if let tHeaders = userOptions["headers"] as? [String:String] {
        for (key, value) in tHeaders {
            request.setValue(value, forHTTPHeaderField: key)
        }
    }

    // Add body data
    let bodyString = userOptions["bodyString"] as? String ?? ""
    request.httpBody = bodyString.data(using: .utf8)

    // Create data task
    let task = URLSession.shared.dataTask(with: request) { data, response, error in
        // If networking error, return early
        guard let data = data, let httpResponse = response as? HTTPURLResponse, error == nil else {
            printError("Error with network while executing POST request: \(error)")
            return
        }

        // Why, oh why, does it not reach here???
    }

    // Start data task
    print("Executing HTTP request: \(request)")
    task.resume()
}
Community
  • 1
  • 1
Crashalot
  • 33,605
  • 61
  • 269
  • 439
  • Besides setting the `httpMethod`, it's worth noting that when you perform a request, you generally use one of the accepted `Content-Type` settings of JSON, XML, or `x-www-form-urlencoded`. What is your web service expecting? It's very, unusual to see a request body that is simply `"Hi"`. How precisely are you parsing the body of the request in your web service? – Rob Nov 03 '16 at 02:48
  • @Rob yup, understood it's unusual, but the goal was to simplify the question as much as possible. Thanks for your help on this question and for supplying the answer to the other question! – Crashalot Nov 03 '16 at 03:02

1 Answers1

1

If you want to do a POST request, not only do you want to set the httpBody, but you also want to set the httpMethod of the request to POST.

request.httpMethod = "POST"
Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • But any clue why it times out when the `httpBody` property is non-empty? – Crashalot Nov 03 '16 at 03:02
  • I assume it stems from creating a request that has a `httpBody` using a default `httpMethod` of `GET`, which never sends any `httpBody`. I wish it handled this more gracefully, though. – Rob Nov 03 '16 at 04:41
  • Thanks. Yup, that's my assumption as well, but technically it shouldn't affect a GET request to send data in the request body, right? – Crashalot Nov 03 '16 at 05:33
  • I'm not going to defend that behavior as it's silly. `GET` requests don't use a body, so, IMHO, it should either send it without the body or, better, generate a warning. – Rob Nov 03 '16 at 05:38
  • OK, thanks. 100% agreed. BTW do you happen to have a suggestion for this issue: http://stackoverflow.com/questions/40334905/xcode-8-use-of-unresolved-identifier-error-even-though-files-share-same-target. Either way, thanks for all your help! – Crashalot Nov 03 '16 at 05:57