URLRequest POST doesn't work in Swift 5. There may be a problem with the server?
Nothing wrong here.
- Status 200
- code doesn’t test for error but I bet it’s nil
- Print of response is what you should expect
- Print JSON prints a json object.
You should be happy. Or What would you expect?
HTTP Request in Swift with POST method
The key is that you want to:
- set the
httpMethod
toPOST
; - optionally, set the
Content-Type
header, to specify how the request body was encoded, in case server might accept different types of requests; - optionally, set the
Accept
header, to request how the response body should be encoded, in case the server might generate different types of responses; and - set the
httpBody
to be properly encoded for the specificContent-Type
; e.g. ifapplication/x-www-form-urlencoded
request, we need to percent-encode the body of the request.
E.g., in Swift 3 and later you can:
let url = URL(string: "https://httpbin.org/post")!
var request = URLRequest(url: url)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
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 ?? URLError(.badServerResponse))
return
}
guard (200 ... 299) ~= response.statusCode else { // check for http errors
print("statusCode should be 2xx, but is \(response.statusCode)")
print("response = \(response)")
return
}
// do whatever you want with the `data`, e.g.:
do {
let responseObject = try JSONDecoder().decode(ResponseObject<Foo>.self, from: data)
print(responseObject)
} catch {
print(error) // parsing error
if let responseString = String(data: data, encoding: .utf8) {
print("responseString = \(responseString)")
} else {
print("unable to parse response as string")
}
}
}
task.resume()
Where the following extensions facilitate the percent-encoding request body, converting a Swift Dictionary
to a application/x-www-form-urlencoded
formatted Data
:
extension Dictionary {
func percentEncoded() -> Data? {
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
}()
}
And the following Decodable
model objects facilitate the parsing of the application/json
response using JSONDecoder
:
// sample Decodable objects for https://httpbin.org
struct ResponseObject<T: Decodable>: Decodable {
let form: T // often the top level key is `data`, but in the case of https://httpbin.org, it echos the submission under the key `form`
}
struct Foo: Decodable {
let id: String
let name: String
}
This checks for both fundamental networking errors as well as high-level HTTP errors. This also properly percent escapes the parameters of the query.
Note, I used a name
of Jack & Jill
, to illustrate the proper x-www-form-urlencoded
result of name=Jack%20%26%20Jill
, which is “percent encoded” (i.e. the space is replaced with %20
and the &
in the value is replaced with %26
).
See previous revision of this answer for Swift 2 rendition.
Swift URL Session and URL Request not working
Your code is structured incorrectly.
URLSession
creates tasks that are run asynchronously. You set up a task, and either pass in a completion block, or set up a delegate.
The task.resume() call returns immediately, long before the network download is complete.
Once the task is complete, the system calls your completion handler (or your delegate, if you use the delegate style).
Beware that URLSessions' completion handlers and delegate calls are done on a background thread. If you do any UIKit calls in response to a task completing, you need to do it on the main thread.
As @keithbhunter says in his comment, you need to put the call to your completion handler inside the completion handler for your task. It's probably safest if you wrap that whole completion handler call in a call to the main thread:
func startConnection(completion: (NSArray, Int) -> Void) {
let url = URL(string: "http://www.example.com/path")
var request : URLRequest = URLRequest(url: url!)
request.httpMethod = "POST"
let postString = "a=\(Int(teamInput.text!)!)"
request.httpBody = postString.data(using: .utf8)
let dataTask = URLSession.shared.dataTask(with: request) {
data,response,error in
print("anything")
do {
if let jsonResult = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary {
self.teamResult = jsonResult
print(jsonResult)
//Use GCD to invoke the completion handler on the main thread
DispatchQueue.main.async() {
completion(NSArray(object: teamResult), Int(teamInput.text!)!)
}
}
} catch let error as NSError {
print(error.localizedDescription)
}
}
dataTask.resume()
}
Note that your force-unwrapping of teamInput.text is very fragile, and will crash if teamInput.text is nil, or if it can't be converted to an Int. You'd be much better off to write your completion handler to take optionals for both the data and the int value you get back from teamInput.text:
func startConnection(completion: (NSArray?, Int?) -> Void) {
and call it passing in an optional:
let value: Int? = teamInput.text != nil ? Int(teamInput.text!) : nil
completion(NSArray(object: teamResult), value)
http Post says its working but it isn't posting on localhost
If you don't see logs in your server, may be caused by URLSession
's cache policy.
Try to set the cachePolicy
property of your URLRequest
to .reloadIgnoringLocalAndRemoteCacheData or .reloadIgnoringCacheData and see if that works:
let url = URL(string: "http://192.168.1.318:8080")! /*localhost*/
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.httpBody = jsonData
request.cachePolicy = .reloadIgnoringLocalAndRemoteCacheData
// or
request.cachePolicy = .reloadIgnoringCacheData
Swift POST Request not working
I figured it out, I had to add in this in my swift file:
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
(iOS / Swift) Simple Post Request with Key-Value Failed, But Succeeded using Postman
Your content type is application/x-www-form-urlencoded
, but you're setting the body as JSON instead of URL-encoded parameters. The way your HTTP body looks with the way you have it now is something like:
{"uname":"21120113120038","pass":"123456"}
...but you want it to look like this:
uname=21120113120038&pass=123456
So, replace this line:
guard let httpBody = try? JSONSerialization.data(withJSONObject: parameter, options: []) else {return}
...with something like this:
guard let httpBody = parameter.map({
[$0.addingPercentEncoding(withAllowedCharacters: .alphanumerics) ?? "",
$1.addingPercentEncoding(withAllowedCharacters: .alphanumerics) ?? ""].joined(separator: "=")
}).joined(separator: "&").data(using: .utf8) else { return }
(However, I think that's a bit messy, so here are some extensions to clean it up somewhat:)
extension String {
var urlEncodedQueryKeyOrValue: String {
return addingPercentEncoding(withAllowedCharacters: .alphanumerics) ?? ""
}
}
extension Dictionary where Key == String, Value == String {
var wwwFormURLEncodedString: String {
return map { "\($0.urlEncodedQueryKeyOrValue)=\($1.urlEncodedQueryKeyOrValue)" }.joined(separator: "&")
}
}
And then you'd use it like this:
[...]
guard let httpBody = parameter.wwwFormURLEncodedString.data(using: .utf8) else { return }
request.httpBody = httpBody
[...]
Swift Alamofire post request doesn't work,
Try removing the '-> Bool' and the 'return resp' from your function to give Alamofire a chance to respond.
How to make HTTP request in Swift?
You can use URL
, URLRequest
and URLSession
or NSURLConnection
as you'd normally do in Objective-C. Note that for iOS 7.0 and later, URLSession
is preferred.
Using URLSession
Initialize a URL
object and a URLSessionDataTask
from URLSession
. Then run the task with resume()
.
let url = URL(string: "http://www.stackoverflow.com")!
let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
guard let data = data else { return }
print(String(data: data, encoding: .utf8)!)
}
task.resume()
Using NSURLConnection
First, initialize a URL
and a URLRequest
:
let url = URL(string: "http://www.stackoverflow.com")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
Then, you can load the request asynchronously with:
NSURLConnection.sendAsynchronousRequest(request, queue: OperationQueue.main) {(response, data, error) in
guard let data = data else { return }
print(String(data: data, encoding: .utf8)!)
}
Or you can initialize an NSURLConnection
:
let connection = NSURLConnection(request: request, delegate:nil, startImmediately: true)
Just make sure to set your delegate to something other than nil
and use the delegate methods to work with the response and data received.
For more detail, check the documentation for the NSURLConnectionDataDelegate
protocol
Testing on an Xcode playground
If you want to try this code on a Xcode playground, add import PlaygroundSupport
to your playground, as well as the following call:
PlaygroundPage.current.needsIndefiniteExecution = true
This will allow you to use asynchronous code in playgrounds.
Related Topics
Skphysicscontact Not Detecting Categorybitmask Collision
How to Draw Something on a PDF in Swift
Sharing Screenshot of Swiftui View Causes Crash
Swift, Detect Ibeacons on The Background and Send Notifications When in Range
Transparent Sticky Header UI Collectionview Don't Show Cells Underneath
How to Store Data from a Picker View in a Variable When a Button Is Pressed
Applescript Used in My Cocoa MAC App, Stopped Working in Osx 10.14
Open Attachment from Mail Using iOS 8 App [Swift]
In Swift Can You Trap "Fatal Error Unexpectedly Found Nil While Unwrapping an Optional Value"
Include Inheritance Constraint in Swift Generic Types
Msmessagelivelayout Freeze/Crash in Transcript When Info.Plist Contains Privacy Request
How to Convert a Pair of Bytes into a Float Using Swift
Streaming .M3U8 Using Mpmovieplayercontroller Does Not Work
Trying to Display Location Data from Firebase to Mapkit
How to Read The Property Values of a JSON Error Object Using Combine in Swift
Swift Corebluetooth Reading a Float Array from Ble
Weird Behaviour in Swiftui+Combine When Class -> Struct
Implement a Custom Staggeregrid in UIview Like Etsy App in Swift