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")
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?
No response from swift post request
Update 1
Okay, after reading your comment, heres whats going on, the program is ending before your code is even being executed. A simple way to see this is if you add a break point in your code.
You can use a semaphore to block the current thread and wait for your URL session to finish.
A dispatch semaphore is an efficient implementation of a traditional
counting semaphore. Dispatch semaphores call down to the kernel only
when the calling thread needs to be blocked. If the calling semaphore
does not need to block, no kernel call is made. Apple
This code will do what you want it to.
var sema = DispatchSemaphore( value: 0 )
let session = URLSession.shared
let url = URL(string: "https://fmsauth.scania.com/auth/S2S4DA/ClientId2Challenge")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
let payload = Data("clientId=cgoxyBxM1KVO3pLm5J7VgDVxlP7_33BpPlPXeIaSmoLsTZq8DfyM1svTwi-SU7KJKBRN4V3mIsV7pNNEg610Xw".utf8)
let task = session.uploadTask(with: request, from: payload) { data, response, error in
if let data = data, let dataString = String(data: data, encoding: .utf8) {
print(dataString)
sema.signal()
}
if let httpResponse = response as? HTTPURLResponse {
print(httpResponse.statusCode)
}
}
task.resume()
sema.wait()
First post
Your code works, I think you need to enable the transport. Add this to info.plist
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>somethingthatshouldntworkyourdomain.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
</dict>
</dict>
Response
Code 200
{"challenge":"eeABaKaf2ZdhPEVQ4ru2S58_j37VLetM3pryIP8uiXk"}
<NSHTTPURLResponse: 0x600003be73e0> { URL: https://fmsauth.scania.com/auth/S2S4DA/ClientId2Challenge } { Status Code: 200, Headers {
"Content-Encoding" = (
gzip
);
"Content-Length" = (
182
);
"Content-Type" = (
"application/json; charset=utf-8"
);
Date = (
"Wed, 15 Jan 2020 21:12:31 GMT"
);
Server = (
"Microsoft-IIS/8.5"
);
"Set-Cookie" = (
"BIGipServerfmsauth.scania.com_https_pool=!c+BZzlVtgeV0E7NCFLoANbUAp39TaIJT2kJgIPLs8cCAJ4R4UMhNbWVOiSnTd/Cx6OuLMGUfIpke3g==; path=/; Httponly; Secure"
);
Vary = (
"Accept-Encoding"
);
"X-HandlingWebServer" = (
sesofms9112
);
"X-Powered-By" = (
"ASP.NET"
);
"owin.RequestId" = (
"4dbeb043-0e55-4972-b955-45c28f94aa77"
);
} }
HTTP Post Request data could not be read Swift 3
A few observations:
You shared PHP that is using
$_POST
. That means it's expectingx-www-form-urlencoded
request. So, in Swift, you should setContent-Type
of the request to beapplication/x-www-form-urlencoded
because that's what you're sending. Likewise, in Swift, theAccept
of the request should beapplication/json
because your code will "accept" (or expect) a JSON response.The
values
string you've supplied has a space in it. There can be no spaces in the key-value pairs that you send in ax-www-form-urlencoded
request. (Note, if you have any non-alphanumeric characters in yourvalues
key pairs, you should be percent encoding them.)In your Swift error handler, in addition to printing the
error
, you might want to try converting thedata
to aString
, and looking to see what it says, e.g.if let string = String(data: data!, encoding: .utf8) {
print(string)
}You might also want to look at
response
and see whatstatusCode
it reported. Having done that, you subsequently told us that it reported astatusCode
of 500.Status code 500 means that there was some internal error in the web service. (The code is 200 if successful.) This is generally a result of some error with the request not being handled correctly. For example, if the request neglected to format the request correctly and the web service doesn't anticipate/catch that, or if there was some other internal error on the web server, you could get 500 error code. For list of status codes, see http://w3.org/Protocols/rfc2616/rfc2616-sec10.html.
If the text in the body of the response from your web service is not illuminating, you might want to turn on error reporting (see How to get useful error messages in PHP? or How do I catch a PHP Fatal Error) and then look at the body of the response again. For example, you might include the following in your PHP:
<?php
function __fatalHandler() {
$error = error_get_last();
//check if it's a core/fatal error, otherwise it's a normal shutdown
if ($error !== NULL && in_array($error['type'], array(E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING))) {
header("Content-Type: application/json");
$result = Array("success" => false, "error" => $error);
echo json_encode($result);
die;
}
}
register_shutdown_function('__fatalHandler');
// the rest of your PHP here
?>
Can't figure out swift POST request error
It looks like your server is returning loginResult instead of serverResponse. Could you try
if let decodedResponse = try? JSONDecoder().decode(loginResult.self, from: data) {
print(decodedResponse)
DispatchQueue.main.async {
self.results = [decodedResponse]
}
return
}
(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
[...]
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.
Related Topics
How Should You Handle Closure Arguments for Uialertaction
Toggle Selection in a List - Swiftui
Swift 3 - Uibutton Adding Settitle from Plist and Database
How to Change Navigationbar Font in Swift
Uiview Background Color in Swift
Building a Spritekit/Gamekit Leaderboard Within a Specific Scene
When Does the Copying Take Place for Swift Value Types
How to Animate Collection View Cells Using Hero Animation
How to Shuffle an Array So That No Two Consecutive Values Are the Same
Alamofire Type 'Parameterencoding' Has No Member 'Url' Swift 3
What Is the Type of the Logical Operators
Uibarbuttonitem Doesn't Work When Created as a Property, But Does When Created in a Function
No Value Associated with Key Codingkeys While Trying to Get Data from Github API in Xcode App
Libsqlite3.Dylib and Libz.Dylib Missing in Xcode 7. How to Use Parse
Get "Does Not Implement Methodsignatureforselector" When Try to Store Array in Nsuserdefaults,Swift
How to Animate Path in Swiftui
Swift, Sprite Kit Game: Have Circle Disappear in Clockwise Manner? on Timer
Swift- Variable Not Initialized Before Use (But It's Not Used)