Alamofire responseSerializationFailed(Alamofire.AFError.ResponseSerializationFailureReason.inputDataNilOrZeroLength) - swift

I had some working code that was getting results from a MySQL DB on a remote web server. It is no longer working and I keep getting the message responseSerializationFailed(Alamofire.AFError.ResponseSerializationFailureReason.inputDataNilOrZeroLength). Here is some code...
Alamofire.request(ADS_URL, method: .get).validate().responseJSON { response in
print("Request: \(String(describing: response.request))") // original url request
print("Response: \(String(describing: response.response))") // http url response
print("Result: \(response.result)") // response serialization result
switch response.result {
case .success(let value):
let json = JSON(value)
print ("JSON: \(json)")
if let data = response.data, let utf8Text = String(data: data, encoding: .utf8) {
print("Data: \(utf8Text)") // original server data as UTF8 string
}
case .failure(let error):
print("Error while querying database: \(String(describing: error))")
return
}
}
I am also using SwiftyJSON. Here are the results of the code...
Request: Optional(http://doyouado.com/adscan/get_ads)
Response: Optional(<NSHTTPURLResponse: 0x17502f3a0> { URL: http://doyouado.com/adscan/get_ads } { status code: 200, headers {
Connection = "keep-alive";
"Content-Length" = 0;
"Content-Type" = "text/html; charset=UTF-8";
Date = "Mon, 18 Sep 2017 16:04:37 GMT";
Server = "nginx/1.12.1";
"Set-Cookie" = "ado_session=a%3A5%3A%7Bs%3A10%3A%22session_id%22%3Bs%3A32%3A%225019d90891c70c81df8ebc2fe754a68f%22%3Bs%3A10%3A%22ip_address%22%3Bs%3A15%3A%22109.150.214.128%22%3Bs%3A10%3A%22user_agent%22%3Bs%3A86%3A%22ADoBroadcaster%2F1.0+%28com.GaryFrank.ADoBroadcaster%3B+build%3A1%3B+iOS+10.3.3%29+Alamofire%2F4.5.0%22%3Bs%3A13%3A%22last_activity%22%3Bi%3A1505750677%3Bs%3A9%3A%22user_data%22%3Bs%3A0%3A%22%22%3B%7D3130ef6f5541e6f944da5a5a1292350bf203fa1b; expires=Mon, 18-Sep-2017 18:04:37 GMT; Max-Age=7200; path=/";
} })
Result: FAILURE
Error: responseSerializationFailed(Alamofire.AFError.ResponseSerializationFailureReason.inputDataNilOrZeroLength)
I have tried using .response and .responseString, but I get no information returned. I am completley stumped. This was all working fine. Hopefully there is someone that can shed some light on this?

Just simply change .responseJSON to .responseData.
And after this parse data:
let jsonDecoder = JSONDecoder()
let parsedData = try jsonDecoder.decode(T.self, from: data)
and no error:
(Alamofire.AFError.ResponseSerializationFailureReason.inputDataNilOrZeroLength)

What worked for me was changing the encoding from JSONEncoding.default to URLEncoding.default!

Updating from Alamofire 4 to 5 caused the issue in my case.
By default, it seems that Alamofire 5 returns the error Alamofire.AFError.ResponseSerializationFailureReason.inputDataNilOrZeroLength for empty response body with status code 200. So adding 200 to the list of emptyResponseCodes resolved the issue for me:
request.responseData(emptyResponseCodes: [200, 204, 205]) { ... } // the default is [204, 205]

What worked for me was changing from .responseData to .response

Commonly this error comes when your API is 'GET' type and you pass 'POST' type.
The same problem I faced and my solution is I replace .post to .get and then this error removed.
For AFNetworking 3.0 :-
go given path,
pods > Pods > AFNetworking > Serialization > AFURLResponseSerialization.m
then replace line no 228 (self.acceptableContentTypes = [NSSet setWithObjects:#"application/json", #"text/json", #"text/javascript", nil];)
with
self.acceptableContentTypes = [NSSet setWithObjects:#"application/json", #"text/json", #"text/javascript", #"text/html", nil];
Because of your response in form of text/html but that is not mentioned in AFNetworking then we add it manually.
Note:- I debugging this problem for Alamofire.

When server sends back no response, Alamofire shows this message in the .failure block if you are printing the error message. Technically it is not an error. Alamofire didn't show this message in its earlier versions, but since one of the recent updates it started showing it.
As I said it is not really an error, but to me its a bug in Alamorfire. And it is very annoying and misleading to keep seeing this in your log when there is no error on your client or server side.
Here is how I silent it:
if (response.data?.count)! > 0 {print(error)}
And I do it when there is no response from the server, which is the expected behaviour since server is not supposed to send response in some cases.
Alamofire.request(MY_URL, method: .get, parameters: ["blabla": blablabla])
.validate(statusCode: 200..<300)
.responseJSON {
response in
switch response.result {
case .success(let value):
self.processResponse(value)
case .failure(let error):
if (response.data?.count)! > 0 {print(error)}
}
}
So the error message doesn't shows when nothing is returned from the server. In my opinion this should be the default behaviour.

Though the question is quite old, I wanted to provide to others what I recently discovered.
Since the error message is very generic and it doesn't help much, check that the url format you are using is correct. I've gotten this only to discover that the url format was incorrect. Once fixed things started working fine.

Related

How to handle 500 http errors

I am trying to access the custom server response body for 500 errors in class HTTPURLResponse (URLResponse) using URLSession.shared.dataTask function. I can only have access to statusCode and allHeaderFields but it doesn't seem to help.
The equivalent in java for ex. is HttpURLConnection.getErrorStream(), but I cannot find something similar in pure swift (I would like to solve this without using 3rd party libs).
How can I get the text response for the 500 error?
let task = session.dataTask(with: urlRequest) { data, response, error in
if let data = data, let response = response as? HTTPURLResponse {
switch response.statusCode {
case 500...599:
let yourErrorResponseString = String(data: data, encoding: .utf8)
default:
break
}
}
}
There is no way you can get the response data out of HTTPURLResponse. It only contains header information.
If you want to retrieve the response data, you need to use something like dataTask(with:completionHandler:) to send your request. That function passes (Data?, URLResponse?, Error?) to your completion handler. The data parameter of the completion handler is the data returned by the server.
For example:
import Foundation
let url = URL(string: "http://httpstat.us/500")!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let data = data, let response = response as? HTTPURLResponse else {
return
}
switch response.statusCode {
case 500...599:
print(String(data: data, encoding: .utf8) ?? "No UTF-8 response data")
default:
print("not a 500")
}
}
task.resume()
Edit: Removed force unwrap according to #Rob‘s suggestion
There is no way to get more details about a 500 error from the client side.
500 is "Internal Server Error" and it's intentionally vague and unhelpful since disclosing information about the cause of the error would assist hackers in compromising the site.
However you can get a great deal of information about the error from the server log and the log for whatever was processing your code on the server side (php, etc.).
If you have access to the server logs and don't see enough information, you can increase the level of logging for the server and application.

Alamofire POST encoding issue

I'm trying to login to a web service as follows:
func Login(completionHandler:#escaping (Bool) -> ()) {
let url = MyUrl
let parameters: Parameters = [
"Password":password,
"StayLoggedIn":NSNumber(value: true),
"UserName":username
]
var headers:HTTPHeaders = commonHeaders()
headers["Content-Type"] = "application/json;charset=UTF-8"
Alamofire.request(url, method:.post, parameters:parameters, headers:headers).responseJSON { response in
switch response.result {
case .success:
debugPrint(response)
case .failure(let error):
print(error)
}
}
}
Somehow, the server returns a 501 error.
I'm in the process of rewriting an Obj-c app in Swift, and replacing NSURLSessions with Alamofire into the bargain.
What I see in my working obj-c app, is that the headers sent to the server contain
Content-Type: application/json;charset=UTF-8
As you can see, I explicitly add this header to my request, but somehow, it is not sent to the server.
What I also see, is that my login credentials are not sent to the server.
So, I guess my question is: how do I tell Alamofire to use the correct encoding/content type?
try this encoding application/x-www-form-urlencoded instead of application/json;charset=UTF-8

Error 401: Alamofire/Swift 3

This code previously works, and suddenly after several works around it stopped and return an Error 401.
Alamofire.request(WebServices.URLS().TabDataURL, method: .post, parameters: reqParams).validate().responseJSON { response in
let statusCode = (response.response?.statusCode) //Get HTTP status code
guard response.result.isSuccess, let value = response.result.value else {
// FIXME:you need to handle errors.
print("Status, Fetching News List:", statusCode)
return
}
I have check via Postman, the parameters are correct. Infact, I can also login (by passing 2 parameters). But when I want to pull in a JSON data from server, I am getting 401.
my main project doesn't have an error. but instead of returning the JSON data, it gave me an Error 401. my other projects (same code format, same server & parameters) is giving me this error.
Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.} it worked!
Also, I have check with my other projects -- it seemed I cannot connect aswell. So I suspect it could be because of Alamofire, or my Xcode?
Anyone can help me?
Hi i think your server Response is not correct because, as error indicate object should not start with array same issue i come across tell backend developer to send response in dictionary,
{NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}
let headers = [String: String]()// To add header if any
Alamofire.request(path,method: mType, parameters: parameters, encoding: JSONEncoding.default, headers : headers) .responseJSON
{ response in
//----- this code always works for me. & You don't need add header if not required.
if let JSON = response.result.value {
print("JSON: \(JSON)")
if response.response?.statusCode == 200
{
successCompletionHandler(JSON as! NSDictionary)
}
else if response.response?.statusCode == 401
{
failureCompletionHandler(JSON as! NSDictionary)
}
else
{
failureCompletionHandler(JSON as! NSDictionary)
}
}
else
{
print("error message")
failureCompletionHandler([WSAPIConst.ERROR:WSAPIConst.ERROR_MESSAGE])
}
}

Alamofire HTTP sent twice SWIFT

every one,
I'm having an issue with Alamofire 3.0, when I post data, it seems the data is being sent twice.
I looked up on the web, found that a bug about special caratères was fixed, but I still get the error.
Anyone has an idea. I'm using a parameter in the header called X-Authorization.
Here is an extract of the code i'm using:
static func postData (url: String,token: String,params :Dictionary<String,AnyObject>){
print("POSTINGGGGGG")
Alamofire.request(.POST, url, parameters: params,headers: ["X-Authorization": token])
.responseJSON { response in
switch response.result {
case .Success(let data): break
//let resultJSON = JSON(data).dictionaryValue
// print(data)
case .Failure(let error):
print(error)
}
}
}
Thank you in advance,
Morgan

How can I retrieve the status message of a request made with Alamofire?

The server that I am using returns error messages in the HTTP status message. For example, it will return "400 User already exists" rather than "400 Bad Request".
I would like to access the string "User already exists" in the response method called by Alamofire. However, I cannot find any way to access this string.
I found this question on StackOverflow already: Swift Alamofire: How to get the HTTP response status code
Unfortunately, no one gives an answer to the question. :(
Here is where Chrome shows where the error is:
I would suggest trying to print out all the possible data fields that you are given and see what you can find. Please try the following example and see if that sheds any light.
let URL = NSURL(string: "your/url/to/somewhere")!
let parameters = ["foo": "bar"]
Alamofire.request(.POST, URL, parameters: parameters)
.response { request, response, data, error in
println("Request: \(request)")
println("Response: \(response)")
println("Error: \(error)")
if let data = data as? NSData {
println("Data: \(NSString(data: data, encoding: NSUTF8StringEncoding)!)")
}
}
Return response in json format from the server and then i think you'll be able to get the appropriate status.
I've implemented that thing using php codeigniter..from where my response is like
$response['status'] = 'user_already_exists';
$this->response($response, 400);
Now in swift you can go with this
Alamofire.request(.POST,URL, parameters:parameters) .responseJSON
{
(request, response, data, error) in
var json = JSON(data!) //I've used swiftyJSON for reading json response
let status = json["status"].stringValue
println("Status : \(status)")
}
Hope this may help you.