Alamofire JSON POST result in Error: The network connection was lost - ios

Several people get this error for different reasons. None of the answers I've found have solved my problem.
I use Timberjack to log my Alamofire requests.
All my GET requests work fine and I receive data in JSON.
My POSTs on the other hand works around 1 out 10 times every time if the POST includes a JSON body.
The server does not specify any Keep-Alive header.
Deployment target is iOS 9.0
This is my shared Manager with Timberjack:
class HTTPManager: Alamofire.Manager{
static let sharedManager: HTTPManager = {
let configuration = Timberjack.defaultSessionConfiguration()
let manager = HTTPManager(configuration: configuration)
return manager
}()
}
Defining the request:
let parameters: [String: AnyObject] = ["status":status]
request = HTTPManager.sharedManager.request(.POST, "\(baseURL)\(uri)", parameters: parameters, encoding: .JSON).validate()
Sending the request:
request!.responseJSON(queue: queue, options: .AllowFragments, completionHandler: { (response) in
//Handling the response
})
Most of the time the server receives an empty JSON body. But sometimes it does work and the body is received and the server responds with an OK. When it doesn't work I receive the error:
Error: The network connection was lost.
FAILURE: Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost."
UserInfo={NSUnderlyingError=0x12fa47cb0 {Error Domain=kCFErrorDomainCFNetwork Code=-1005 "The network connection was lost."
If someone can explain what's happening here I would be forever grateful :)
EDIT 1
We let the server respond every call with "Connection": "close" which did nothing to help the problem. The app always sends "Connection": "keep-alive" by default and it cannot be changed. Could this be the problem? That the app thinks the connection is open even though it's closed by the server? But even though you wait a few minutes it seems as though the POST call only works at random.
EDIT 2
Even when I wait 30 seconds between GET(s) and/or POST(s). GET always works. POST works at random (rarely). I get the -1005 error on most POSTs. Even though I get the network connection was lost error the server still receive my request but the JSON body is missing.
EDIT 3 - Ugly solution
In my response I check for the error code -1005, when I receive this error I just recreate the request and try again. This results in sending around 2-4 POST requests to the server where one POST works and the rest have empty JSON bodies.

Restart simulator or kill your app by throwing out from tasks.
Or check more solutions to this error code:
NSURLErrorDomain Code -1005 The network connection was lost

Related

iOS Alamofire - Streaming JSON lines first response issue

Using Alamofire 4.9.0.
I am trying to implement handling streaming APIs in JSON lines format. Here's how:
stream = Alamofire.request(url, method: HTTPMethod.get,
headers: TTSessionManager.headers)
.validate()
.stream(closure: { (data) in
// parsing JSON lines ...
})
.response(completionHandler: { (response) in
// error handling ...
})
Now the issue is that the first response takes some time to return. And when it does I get a couple of JSON lines in one big batch. After that stream continues to normally respond with a new JSON line per response coming through the stream.
Has anyone encountered this behaviour? I'm wondering wether there is some additional session or request setup needed in order for this to work normal (line per response) from the start. When inspecting the response.metrics after canceling the request a lot of the fields are null so I can't for sure say wether some of the initial connection steps are the issue:
(Domain Lookup Start) (null)
(Domain Lookup End) (null)
(Connect Start) (null)
(Secure Connection Start) (null)
(Secure Connection End) (null)
(Connect End) (null)
So the problem here was that the response header didn't have Content-Type set to application/json. When this header is not set properly, URLSession data task will buffer first 512 bytes of response.
More info can be found here: https://developer.apple.com/forums/thread/64875

API request times out ONLY if I pass parameters

I am trying to figure out why any time I pass valid json to my server for a GET request the connection times out. I do not have any problems passing json to my server in any other request type other than GET... I've tested the server-side code locally and the queries work as expected.
I want to fetch a specific user from my database and I need to pass in a username, so I send the username to the server.
The error I keep getting (If I don't send any paramaters to the server, and just return current_user, it works and I don't get this error)
Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo={NSUnderlyingError=0x604000454c40 {Error Domain=kCFErrorDomainCFNetwork Code=-1001
Here is the part of the API call code where I set the request type and values to send to the server, in case:
let request = NSMutableURLRequest(url: url as URL)
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.httpBody = jsonData
request.httpMethod = "GET"
Server set up, just in case it matters:
Digitalocean droplet, Linux, Ubuntu 16.04, Nginx
EDIT/ UPDATE
If I change the method from a GET to a POST (and keep the server code exactly the same), the server sends the correct data back immediately.
The server side code for this is very short, so I really don't see how it can be timing out due to optimization:
user = UserModel.find_by_username(data['username'])
if user:
return {"response": [user.json()]}, 200
return {"response": "user not found"}, 404
It really seems as if we can't send json via a GET method. It doesn't seem to work on both a simulator nor an actual device...I saw a similar SO post where someone commented exactly what I'm experiencing. Changing GET to POST was the fix....but it is a GET request, so why wouldn't this work?
GET-Method does not support http body. When you send your parameter as url encoded it will work.
Example:
http://www.example.de?username=abc

Network errors in Alamofire

I am a newbie to iOS and using Alamofire in my app. Everything is working fine. Now I want to implement network errors. I have searched about it and here are my findings:
We can implment request timed out in the following way:
let manager = Alamofire.SessionManager.default
manager.session.configuration.timeoutIntervalForRequest = 10
let urlVerifyEmail = ####
manager.request(urlVerifyEmail, method: .post, parameters: ["user_email" : email], encoding: JSONEncoding.default, headers: nil).responseJSON(completionHandler: { response in
switch response.result {
case .success:
print (“success”)
case .failure(let serverError):
if (serverError._code == NSURLErrorTimedOut)
{
print(”Request timed out”)
}
else
{
print(”Error sending request to server”)
}
}
}
)
I have read there official docs too. However I am not having much clarity.
What does request timed out actually mean? Does it mean that the app is taking too long to send the request? or server is taking too long to send the response back?
What are other types or network errors in Alamofire? What if the connection wasn't successfully made? What if it broke while the request was getting sent? What if it broke while the response was coming back?
If error code for request timed out is -1001 then what are the codes for other network errors? In order to provide the users with the best experience, which is the best approach to cover all of network errors?

Websocket : Starscream "masked and rsv data is not currently supported"

I am developing an iOS app which required to connect with web socket server.
I can successfully connect to server but when I send request on it, it drop off the connection.
I am using Starscream library for web socket.
As per server support team:
it does not support protocol compression, but in the headers below they're requesting "permessage-deflate" from us. We'll accept uncompressed messages just fine (it's just a flag on the packet) but due to the extension they asked for, messages we send out will be compressed with that flag set.
I send request as following using Swift
let dict = ["Parameter1":"value1","Parameter2":"value2"]
do {
let data = try NSJSONSerialization.dataWithJSONObject(dict, options: NSJSONWritingOptions(rawValue: 0))
var jsonString: String = String(data: data, encoding: UInt())!
self.socket.writeString(jsonString);
} catch {
print(error)
}
It disconnect with server and print following message.
"websocket is disconnected: Optional("masked and rsv data is not currently supported")"
What the server support team meant is that the request from your WebSocket client application contained an HTTP header like below.
Sec-WebSocket-Extensions: permessage-deflate
So, if your application has a line like below, remove it.
socket.headers["Sec-WebSocket-Extensions"] = "permessage-deflate"
This error might also be thrown if the server doesn't accept the incoming connection (regardless of the reasons), or if the server crashed.
Basically, when this message shows up, the best action would be to check what is going on the server as you might be wasting time trying improve client code (it happened to me :)
For those facing this issue when trying to connect to the backend WebSocket, make sure the front end and the backend version of the socket.io are compatible. Running the following command fixed the issue for me.
pod update
Updated the both to the latest and solved the issue.
this will fix your issue I believe. just add "wamp" in the header like this.
*
var request = URLRequest(url: URL(string: URL)!)
request.setValue(["wamp"].joined(separator: ","), forHTTPHeaderField: "Sec-WebSocket-Protocol")
socket = WebSocket(request: request)
socket.delegate = self
socket.connect()

Cannot download image using AFHTTPRequestOperationManager

I'm trying to download an image (jpeg) from a given URL using this code:
let manager = AFHTTPRequestOperationManager()
manager.responseSerializer = AFImageResponseSerializer()
manager.responseSerializer.acceptableContentTypes = NSSet(array: ["application/octet-stream"]) as Set<NSObject>
manager.GET(imageURL, parameters: nil,
success: { (operation: AFHTTPRequestOperation!, responseObject: AnyObject!) -> Void in
println("IMAGE SUCCESS")
}, failure: { (operation: AFHTTPRequestOperation!, error: NSError!) in
println("IMAGE FAIL")
})
With my internet at the moment, the success block is being called when testing on the simulator. However, the failure block is being called when testing on an iPhone. On another network, the success block is always called on both iPhone and simulator.
I can't figure out what's causing the issue. I have tried setting the Content-Type to "image/jpeg" but still got the same results. Did I miss something?
The error is:
Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo=0x1675f381 {NSErrorFailingURLStringKey=<...>, NSErrorFailingURLKey=<...>, NSLocalizedDescription=The request timed out., NSUnderlyingError=0x166c7891 "The request timed out."}
Are you requesting many images (or doing many network requests)? If so, you might want to constrain the AFHTTPRequestOperationManager:
manager.operationQueue.maxConcurrentOperationCount = 5
If you don't do this and then proceed to initiate many requests, the "timeout" starts when the network requests are enqueued even though NSURLConnection (which AFHTTPRequestOperationManager uses behind the scenes) can only run 4 or 5 at a time and the latter requests may not even start until earlier ones finish. You want to start the timeout logic for network requests on the basis of when the request starts, not when the request was enqueued. By constraining the maxConcurrentOperationCount, you're ensuring that network requests aren't initiated before they can reasonably be performed.
Note, that presumes that you use the same AFHTTPRequestOperationManager for all of your requests, not instantiating new operation managers for new requests. But this will ensure that requests aren't started until the backlog of other requests has been reduced to an acceptable level.
--
As an aside, rather than replacing acceptableContentTypes, I'd merely suggest augmenting it:
var acceptableContentTypes = manager.responseSerializer.acceptableContentTypes ?? Set<NSObject>()
acceptableContentTypes.insert("application/octet-stream")
manager.responseSerializer.acceptableContentTypes = acceptableContentTypes
Frankly, I'd rather see you fix the Content-Type of the images you're retrieving from the server so that it didn't send application/octet-stream responses, but if you can't do that, the above is probably a more prudent way to adjust the content types. This ensures that you accept both your custom application/octet-stream type, as well as the standard image types.

Resources