Error Code=-1005 "The network connection was lost." in Swift while consuming Web Service - ios

I'm working on a iOS project in Swift 2.0, which has Web service calls, these services are slow to respond and that is normal, can be up to 1 minute or a little more, when i call the service 70% of the time it answers with the error "the network connection was lost." The tests were conducted in both simulator and different phone devices and iPad and the result is the same. The network connection is strong and the same application was also created on Android and working properly almost 100% of the time.
The way I call services from any view is as follows:
#IBAction func contratarAct(sender: AnyObject) {
conexion.delegate = self
loadingView = MEXLoadingView(delegate: self, title: "Espere por favor", percent: false, view: self.view)
self.loadingView.showAnimated(true)
let url = urlServicios.urlBaseServicios + "/" + idSolicitud + "/" + idNoCliente + "/CONTRATO"
conexion.consultaServicioGET(url, httpMethod: "PUT")
}
And the method that is executed is as follows:
func consultaServicioGET(url : String, httpMethod : String ){
let urlString = url
let request = NSMutableURLRequest(URL: NSURL(string: urlString)!)
request.timeoutInterval = 540
request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalAndRemoteCacheData
request.addValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
var session = NSURLSession.sharedSession()
request.HTTPMethod = httpMethod
let urlconfig = NSURLSessionConfiguration.defaultSessionConfiguration()
urlconfig.timeoutIntervalForRequest = 540
urlconfig.timeoutIntervalForResource = 540
session = NSURLSession(configuration: urlconfig, delegate: self, delegateQueue: nil)
let task = session.dataTaskWithRequest(request , completionHandler: {
(data:NSData?, response:NSURLResponse?, error:NSError?) in
if error != nil {
let jsonError : NSDictionary = NSDictionary()
self.delegate?.respuestaServicioGET!(jsonError, mensaje: "\(error!.localizedDescription)")
return
}
let jsonString = NSString(data: data!,encoding: NSASCIIStringEncoding)
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
let json: NSDictionary = try! NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
if (json.isKindOfClass(NSDictionary) ){
self.delegate?.respuestaServicioGET!(json, mensaje: "OK")
}else{
let jsonError : NSDictionary = NSDictionary()
self.delegate?.respuestaServicioGET!(jsonError, mensaje: "ERROR")
}
})
task.resume()
}
the error displayed is:
error=Optional(Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost." UserInfo={NSUnderlyingError=0x7fbde5f51df0 {Error Domain=kCFErrorDomainCFNetwork Code=-1005 "(null)" UserInfo={_kCFStreamErrorCodeKey=-4, _kCFStreamErrorDomainKey=4}}, NSErrorFailingURLStringKey=https://particulares-gw-obparticularesmx-pre.appls.cto2.paas.gsnetcloud.com:443/OPB/57dadf7de4b0ac2e518de44a/57dadf7de4b06c6b04ef0dcf/CONTRATO, NSErrorFailingURLKey=https://particulares-gw-obparticularesmx-pre.appls.cto2.paas.gsnetcloud.com:443/OPB/57dadf7de4b0ac2e518de44a/57dadf7de4b06c6b04ef0dcf/CONTRATO, _kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-4, NSLocalizedDescription=The network connection was lost.})
I add some code like the following:
urlconfig.timeoutIntervalForRequest = 540
urlconfig.timeoutIntervalForResource = 540
Trying to get more "timeout" but this is not looks like a timeout.
I can not get out of this error for days, any help will be greatly appreciated. I'm desperate.

If you're expecting a socket to stay open for minutes at a time, you're in for a world of hurt. That might work on Wi-Fi, but on cellular, there's a high probability of the connection glitching because of tower switching or some other random event outside your control. When that happens, the connection drops, and there's really nothing your app can do about it.
This really needs to be fixed by changing the way the client requests data so that the responses can be more asynchronous. Specifically:
Make your request.
On the server side, immediately provide the client with a unique identifier for that request and close the connection.
Next, on the client side, periodically ask the server for its status.
If the connection times out, ask again.
If the server says that the results are not ready, wait a few seconds and ask again.
On the server side, when processing is completed, store the results along with the identifier in a persistent fashion (e.g. in a file or database)
When the client requests the results for that identifier, return the results if they are ready, or return a "not ready" error of some sort.
Have a periodic cron job or similar on the server side to clean up old data that has not yet been collected.
With that model, it doesn't matter if the connection to the server closes, because a subsequent request will get the data successfully.

I faced the same issue and I am attaching a screenshot of the resolution to show how I resolved the issue.
In my case, the issue was that the API requests are blocked from the server Sucuri/Cloudproxy (Or you can say firewall service). Disabling the firewall resolved the issue

I don't why but it's works when I add sleep before my request:
sleep(10000)
AF.request(ViewController.URL_SYSTEM+"/rest,get_profile", method: .post, parameters: params, encoding: JSONEncoding.default , headers: headers).responseJSON { (response) in
}

I faced this issue and spend more than 1 week to fix this. AND i just solved this issue by changing Wifi connection.

Related

Alamofire post method in iOS Swift 4?

For getting push notification here i am sending postitem, token, like count and currentname using alamofire post method(pod version alamofire 4.5). I did not get any response when post method called and it does not show any errors.
I tried keeping breaking points in alamofire function, it call alamofire.requestion then it goes out function.
Here is the code tried to send post method to backend:
func postNotification(postItem: String, post: Post) {
print("Get token from post:::",post.token)
print(postItem)
let token = UserDefaults.standard.string(forKey: "token")
let headers: HTTPHeaders = ["Content-Type" :"application/x-www-form-urlencoded"]
let parameters : [String:Any] = ["count":post.likeCount!, "likedby":currentName, "postId=":postItem, "token": post.token!]
Alamofire.request("http://highavenue.co:9000/likesnotification/", method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: nil).responseJSON { (response:DataResponse<Any>) in
switch(response.result) {
case .success(_):
if let data = response.result.value{
print(data)
}
break
case .failure(_):
print(response.result.error as Any)
break
}
}
}
Getting console error like this
2018-07-10 14:21:07.980212+0530 HighAvenue[10584:4236493] Task <B5FC98AB-C3FE-
4D4F-9A93-72D3FFE35DF7>.<1> finished with error - code: -1001
Optional(Error Domain=NSURLErrorDomain Code=-1001 "The request timed out."
UserInfo={NSUnderlyingError=0x1c0e478f0 {Error Domain=kCFErrorDomainCFNetwork Code=-1001 "(null)" UserInfo={_kCFStreamErrorCodeKey=-2102, _kCFStreamErrorDomainKey=4}}, NSErrorFailingURLStringKey=http://highavenue.co:9000/likesnotification/, NSErrorFailingURLKey=http://highavenue.co:9000/likesnotification/, _kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-2102, NSLocalizedDescription=The request timed out.})
That is because you are not setting request time in your network call, by default your request time is a small interval, so please increase request timeout time. something like this,
let request = NSMutableURLRequest(url: URL(string: "")!)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.timeoutInterval = 120 // 120 secs
let values = ["key": "value"]
request.httpBody = try! JSONSerialization.data(withJSONObject: values, options: [])
Alamofire.request(request as! URLRequestConvertible).responseJSON {
response in
// do whatever you want here
}
Second mistake in your code is you are trying to access http url which are by default are not allowed so you have to by pass this security from your app, Please refer to this answer in order to remove this security layer from your app.
The resource could not be loaded because the App Transport Security policy requires the use of a secure connection

TIC TCP Conn Failed when running Swift project on my phone

I am new to Swift. I built a simple application which works fine on the simulator. I am running the same on my device (iPhone 6s with iOS 11.0.2) and it's failing to connect to server.
getting these errors:
2017-10-26 18:16:02.489134-0400 myproj[1451:206438] TIC TCP Conn Failed [1:0x1c0176800]: 1:61 Err(61)
2017-10-26 18:16:02.489771-0400 myproj[1451:206438] Task <0C30ADDC-4A0E-4815-A701-2EF0A7CF5F04>.<1> HTTP load failed (error code: -1004 [1:61])
2017-10-26 18:16:02.490293-0400 myproj[1451:206440] Task <0C30ADDC-4A0E-4815-A701-2EF0A7CF5F04>.<1> finished with error - code: -1004
Please help me understand this error.
EDIT:
Here is the code making that call to the server:
func postRequest(postData: NSDictionary, postHeaders: NSDictionary, endPoint: String,
onComplete: #escaping ((NSDictionary)->Void), callbackParams: NSDictionary = NSMutableDictionary()) {
let url:URL = baseUrl.appendingPathComponent(endPoint)
let session = URLSession.shared
let request = NSMutableURLRequest(url: url)
request.httpMethod = "POST"
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
var paramString = ""
for (key, value) in postData{
paramString = paramString + (key as! String) + "=" + (value as! String) + "&"
}
request.allHTTPHeaderFields = postHeaders as? [String : String]
request.httpBody = paramString.data(using: String.Encoding.utf8)
let task = session.dataTask(with: request as URLRequest, completionHandler: {
(data, response, error) in
guard let _:Data = data, let _:URLResponse = response , error == nil else {
return}
let json: Any?
do {
json = try JSONSerialization.jsonObject(with: data!, options: [])
}
catch {
return
}
var serverResponse = json as? NSDictionary
DispatchQueue.main.async{
for (key, value) in serverResponse!{
callbackParams.setValue(value, forKey: key as! String)
}
onComplete(callbackParams)
}
})
task.resume()
}
EDIT:
Thanks!
Error -1004 is URLError.cannotConnectToHost. It cannot connect to the server for some reason.
In comments, you say the URL is http://127.0.0.1. That is localhost, the current machine. If you use that URL on a physical phone, it's going to look for the web server on the phone. Lol. It works on the simulator, because the simulator is your computer, the localhost.
You need a URL that your iPhone can resolve to the machine running your web service. For example, find out what the IP for the computer running the web service on your local network, make sure your iPhone is on wifi on the same network, and then use that unique IP number for your computer on the LAN (likely something more like 192.168.0.x).
I was getting the same problem when i was sending/ receiving socket messages! I am using Socket.io and Firebase for push and the error was at the node.js backend. The error was that the mongoose version was deprecated. Whenever this error arises at the iOS End, ask the node.js backend team to look for Red color crash logs. They will surely find the problem causing this error on frontend. Hope this helps !!
In my case i'm not changes the Local host IP address.
Example : #"http://Localhost/Host name/index.pnp/apiname?";
initially i'm used above URL, so i'm got the same error...
Later i changed in to Localhost to 190.177.0.22
Example : #"http://190.177.0.22/Host name/index.pnp/apiname?";
Another corner case if you using something like ngrok and it's still not working is the phone isn't connected to a service provider network or wifi.
In my case my main phone was working the second out of service phone was not.

Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost

I am getting this error when using SwiftyBeaver logger, which tries to send data to the cloud via this code:
func sendToServerAsync(str: String?, complete: (ok: Bool, status: Int) -> ()) {
if let payload = str, let queue = self.queue {
// create operation queue which uses current serial queue of destination
let operationQueue = NSOperationQueue()
operationQueue.underlyingQueue = queue
let session = NSURLSession(configuration:
NSURLSessionConfiguration.defaultSessionConfiguration(),
delegate: nil, delegateQueue: operationQueue)
// assemble request
let request = NSMutableURLRequest(URL: serverURL)
request.HTTPMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
// basic auth header
let credentials = "\(appID):\(appSecret)".dataUsingEncoding(NSUTF8StringEncoding)!
let base64Credentials = credentials.base64EncodedStringWithOptions([])
request.setValue("Basic \(base64Credentials)", forHTTPHeaderField: "Authorization")
// POST parameters
let params = ["payload": payload]
do {
request.HTTPBody = try NSJSONSerialization.dataWithJSONObject(params, options: [])
} catch let error as NSError {
toNSLog("Error! Could not create JSON for server payload. \(error)")
}
//toNSLog("sending params: \(params)")
//toNSLog("\n\nbefore sendToServer on thread '\(threadName())'")
sendingInProgress = true
// send request async to server on destination queue
let task = session.dataTaskWithRequest(request) {
_, response, error in
var ok = false
var status = 0
//toNSLog("callback of sendToServer on thread '\(self.threadName())'")
if let error = error {
// an error did occur
self.toNSLog("Error! Could not send entries to server. \(error)")
} else {
if let response = response as? NSHTTPURLResponse {
status = response.statusCode
if status == 200 {
// all went well, entries were uploaded to server
ok = true
} else {
// status code was not 200
var msg = "Error! Sending entries to server failed "
msg += "with status code \(status)"
self.toNSLog(msg)
}
}
}
return complete(ok: ok, status: status)
}
task.resume()
}
}
The strange thing is it works for the first two or three log entries, and then stops due to the above error. I tried to reset content and settings on the simulator and reboot my simulator (as suggested in Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost.") but that just fixes it temporarily--after the first 2-3 log entries, it starts failing again.
I tried debugging this for hours with the creator of SwiftBeaver last night, but we couldn't get it to work. Seems like not many people are seeing this issue.
I tried removing my Wifi connection and reconnecting, but that didn't work either.
Any guidance on this would be much appreciated.
FYI, I'm using Swift 2 and XCode 7.3.
This is probably caused by HTTP keep-alive support being seriously buggy in the iOS simulator. See:
Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost."
for more details, but the short answer is to disable keep-alive on the server that you use when doing simulator testing, or better yet, add some logic that immediately retries the request if it sees that particular error.

POST Request gives timeout when testing on iPhone device

I'm working on a school project, which is developing a Web application with an API and an iPhone app with swift. I developed the website in Laravel with Homestead/Vagrant.
But when it comes to the iPhone app, i'm facing with a problem:
When a user presses the login button the app sends a http POST request to the API and the API checks if the users exists in the db, if so then it will return a token, after which the user will be redirected to the dashboard. This works fine on the xcode simulator.
My code of the request part looks like this:
var loginUrl = "http://10.1.1.33/api/login" + "?email=" + self.email + "&password=" + self.password
let request = NSMutableURLRequest(URL: NSURL(string: loginUrl)!)
let session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
let task = session.dataTaskWithRequest(request, completionHandler: {
data, response, error -> Void in
guard error == nil else {
print("First Error!!! \(error)")
self.errorLabel.text = "Request timed Out"
self.enableLoginBtn(true, buttonText: "Login")
return
}
do {
let data: AnyObject? = try NSJSONSerialization.JSONObjectWithData(data!, options: [])
// Okay, the `json` is here, let's get the value for 'success' out of it
let json = JSON(data!)
dispatch_async(dispatch_get_main_queue(), {
if json["token"] != nil {
print("Login successvol!)")
if self.saveSession(json["token"].string!) {
self.enableLoginBtn(true, buttonText: "Login")
self.goToDashboard()
}else {
print("Saving token went wrong")
}
}else {
self.showError("Gebruikersnaam of wachtwoord is onjuist")
self.enableLoginBtn(true, buttonText: "Login")
}
})
}catch let parseError{
print(parseError)
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Error could not parse JSON: \(jsonStr)")
self.enableLoginBtn(true, buttonText: "Login")
}
})
task.resume()
But when i try to test the exact same thing on my iPhone 5s (I have a developer license) it's failing every single time. The error i'm getting is:
Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo=0x1742e1e80 {NSUnderlyingError=0x170259230 "The operation
couldn’t be completed. (kCFErrorDomainCFNetwork error -1001.)",
NSErrorFailingURLStringKey=http://10.1.1.33/api/login?email=jejz#kdk.nl&password=sndxbdj,
NSErrorFailingURLKey=http://10.1.1.33/api/login?email=jejz#kdk.nl&password=sndxbdj,
NSLocalizedDescription=The request timed out.}
The last couple days i searched the whole internet for a solution, but i couldn't find any solution.
I'd be really grateful if someone can help me out with this.
Thanks in advance.
Best regards
EDITED ---------------------
Screenshot of the error
I think you might be confused about POST and GET requests.
POST parameters are sent in the Request body, while in the GET request the parameters are sent in the URL.
GET Method parameters example:
/test/demo_form.asp?name1=value1&name2=value2
POST Method parameters example:
POST /test/demo_form.asp HTTP/1.1
Host: w3schools.com
name1=value1&name2=value2
So what you are trying to do, is send the parameters in the URL with the POST request, which is why it doesn't work!
You need to put the parameters in the Request body!
What you need to do is:
1. Change the request URL
var loginUrl = "http://10.1.1.33/api/login"
2. Add the parameters in the Request body
let postString = "email=" + self.email + "&password=" + self.password
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding);
If you are using iOS 9, this is due to the new Transport security setting that is enabled by default. It blocks all outgoing non https requests. There is a way to turn it off for all requests, so any http request will load. There is also a way to control each url or url wildcard that can load on http.
If you are using http for your login, I suggest you change your server to support SSL and TLS 2.0 (pretty much the standard on most hosts with https) rather than turning it off to load http. Usernames and passwords shouldnt go over http.
If however you need to turn it off for furthering the development until you get a certificate setup, here is how to do it.
Add this to your info.plist file (open it in source code mode, control click on the file and select)
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
If you want to control specific urls, you can use <key>NSExceptionDomains</key>

Swift: error when trying to communicate with web API

I am trying to build a really basic iOS app using Swift - this is my first time doing so. Whilst the majority of it has been really straight forward. I have had a total nightmare getting the app to talk to my API, or any site in general!
This is the code i'm using, and specifically the code which is erroring:
NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
println(NSString(data: data, encoding: NSUTF8StringEncoding))
})
it's the 'NSString(data: data, encoding: NSUTF8StringEncoding)' that errors
I've gone through as many tutorials as I can find, and they all return me the same problem. I get an error saying:
NSURLErrorDomain - code: 4294966291
I also get a 'EXC_BAD_INSTRUCTION' error with: EXC_1386_INVOP, sub code = 0x0 (which hasn't led me to a solution...
Which makes me think that I haven't done something right in my set up, or something should be turned on in my preferences, or something along those lines as opposed to my code...
this is my whole code:
var URL: NSURL = NSURL(string: "http://stackoverflow.com")
var request:NSMutableURLRequest = NSMutableURLRequest(URL:URL)
request.HTTPMethod = "POST"
var bodyData = "key1=value&key2=value&key3=value"
println(URL)
println(bodyData)
request.HTTPBody = bodyData.dataUsingEncoding(NSUTF8StringEncoding);
let queue:NSOperationQueue = NSOperationQueue()
NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
println(NSString(data: data, encoding: NSUTF8StringEncoding))
})
Update:
Using Rob's code, I know get an error printed:
sendAsynchronousRequest error: Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost." UserInfo=0x7beafcc0 {NSErrorFailingURLStringKey=http://stackoverflow.com, _kCFStreamErrorCodeKey=57, NSErrorFailingURLKey=http://stackoverflow.com, NSLocalizedDescription=The network connection was lost., _kCFStreamErrorDomainKey=1, NSUnderlyingError=0x7d154ca0 "The network connection was lost."}
It sounds like data is nil. Examine the contents of the error object, and it should give you an indication of why. Most likely, there's something wrong with the request, but unless we can reproduce the problem, it's hard to diagnose.
Anyway, if you want to perform the request with a little more diagnostic information (log error if there is a problem, log statusCode and response if status code was not 200, etc.):
NSURLConnection.sendAsynchronousRequest(request, queue: queue) {
response, data, error in
if data == nil {
println("sendAsynchronousRequest error: \(error)")
return
}
if let httpResponse = response as? NSHTTPURLResponse {
let statusCode = httpResponse.statusCode
if statusCode != 200 {
println("sendAsynchronousRequest status code = \(statusCode); response = \(response)")
}
}
println(NSString(data: data, encoding: NSUTF8StringEncoding))
}
In your revised question, you shared the resulting NSError, which reported -1005 (which, in retrospect, is the same as the 4294966291 error code you showed us earlier; the latter being the the unsigned integer representation of -1005). This error (as the description describes) is for NSURLErrorNetworkConnectionLost (which is kCFURLErrorNetworkConnectionLost), for which the documentation says, "Returned when a client or server connection is severed in the middle of an in-progress load."
Unfortunately, this error is used for a diverse array of issues, and as I'm unable to reproduce the error you describe, it's hard to diagnose.
One thing that is missing from the request is the specification of the Content-Type:
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
That wouldn't cause the problem you describe, but it's good practice to always inform the server of the type of the request.
I solved this, partly thanks to Rob's answers and general help - that was very useful.
The Key in the end though, was super simple and taken from this question: Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost."
I just had to restart the simulator. However I wouldn't have gotten there without the additional if data == nil {} statement.

Resources